move assignment operators for folly::Synchronized
[folly.git] / folly / Uri.cpp
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "folly/Uri.h"
18
19 #include <ctype.h>
20 #include <boost/regex.hpp>
21
22 namespace folly {
23
24 namespace {
25
26 fbstring submatch(const boost::cmatch& m, size_t idx) {
27   auto& sub = m[idx];
28   return fbstring(sub.first, sub.second);
29 }
30
31 template <class String>
32 void toLower(String& s) {
33   for (auto& c : s) {
34     c = tolower(c);
35   }
36 }
37
38 }  // namespace
39
40 Uri::Uri(StringPiece str) : port_(0) {
41   static const boost::regex uriRegex(
42       "([a-zA-Z][a-zA-Z0-9+.-]*):"  // scheme:
43       "([^?#]*)"                    // authority and path
44       "(?:\\?([^#]*))?"             // ?query
45       "(?:#(.*))?");                // #fragment
46   static const boost::regex authorityAndPathRegex("//([^/]*)(/.*)?");
47
48   boost::cmatch match;
49   if (UNLIKELY(!boost::regex_match(str.begin(), str.end(), match, uriRegex))) {
50     throw std::invalid_argument("invalid URI");
51   }
52
53   scheme_ = submatch(match, 1);
54   toLower(scheme_);
55
56   StringPiece authorityAndPath(match[2].first, match[2].second);
57   boost::cmatch authorityAndPathMatch;
58   if (!boost::regex_match(authorityAndPath.begin(),
59                           authorityAndPath.end(),
60                           authorityAndPathMatch,
61                           authorityAndPathRegex)) {
62     // Does not start with //, doesn't have authority
63     path_ = authorityAndPath.fbstr();
64   } else {
65     static const boost::regex authorityRegex(
66         "(?:([^@:]*)(?::([^@]*))?@)?"  // username, password
67         "(\\[[^\\]]*\\]|[^\\[:]*)"     // host (IP-literal, dotted-IPv4, or
68                                        // named host)
69         "(?::(\\d*))?");               // port
70
71     auto authority = authorityAndPathMatch[1];
72     boost::cmatch authorityMatch;
73     if (!boost::regex_match(authority.first,
74                             authority.second,
75                             authorityMatch,
76                             authorityRegex)) {
77       throw std::invalid_argument("invalid URI authority");
78     }
79
80     StringPiece port(authorityMatch[4].first, authorityMatch[4].second);
81     if (!port.empty()) {
82       port_ = to<uint32_t>(port);
83     }
84
85     username_ = submatch(authorityMatch, 1);
86     password_ = submatch(authorityMatch, 2);
87     host_ = submatch(authorityMatch, 3);
88     path_ = submatch(authorityAndPathMatch, 2);
89   }
90
91   query_ = submatch(match, 3);
92   fragment_ = submatch(match, 4);
93 }
94
95 }  // namespace folly