]> git.tdb.fi Git - libs/net.git/blob - source/utils.cpp
Style update: spaces around assignments
[libs/net.git] / source / utils.cpp
1 /* $Id$
2
3 This file is part of libmsphttp
4 Copyright © 2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <algorithm>
9 #include <msp/strings/formatter.h>
10 #include <msp/strings/regex.h>
11 #include <msp/strings/utils.h>
12 #include "utils.h"
13
14 using namespace std;
15
16 namespace {
17
18 const char *reserved[]=
19 {
20         " #%&+=?",
21         " #%&*+:;=?@[]",
22         " !#$%&'()*+,/:;=?@[]",
23 };
24
25 bool is_reserved(char c, unsigned level)
26 {
27         for(const char *r=reserved[level]; *r; ++r)
28                 if(c==*r)
29                         return true;
30         return false;
31 }
32
33 }
34
35 namespace Msp {
36 namespace Http {
37
38 string urlencode(const string &str, EncodeLevel level)
39 {
40         string result;
41         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
42         {
43                 if(is_reserved(*i, level))
44                         result += format("%%%02X", *i);
45                 else
46                         result += *i;
47         }
48         return result;
49 }
50
51 string urlencode_plus(const string &str, EncodeLevel level)
52 {
53         string result;
54         for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
55         {
56                 if(*i==' ')
57                         result += '+';
58                 else if(is_reserved(*i, level))
59                         result += format("%%%02X", *i);
60                 else
61                         result += *i;
62         }
63         return result;
64 }
65
66 string urldecode(const string &str)
67 {
68         string result;
69         for(unsigned i=0; i<str.size(); ++i)
70         {
71                 char c = str[i];
72                 if(c=='%')
73                 {
74                         if(i+3>str.size())
75                                 throw InvalidParameterValue("Malformed data");
76                         result += lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
77                         i += 2;
78                 }
79                 else if(c=='+')
80                         result += ' ';
81                 else
82                         result += c;
83         }
84         return result;
85 }
86
87 Url parse_url(const string &str)
88 {
89         static Regex r_url("(([a-z]+)://)?([a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*(:[0-9])?)?(/[^?#]*)?(\\?([^#]+))?(#(.*))?");
90         if(RegMatch m = r_url.match(str))
91         {
92                 Url url;
93                 url.scheme = m[2].str;
94                 url.host = m[3].str;
95                 url.path = urldecode(m[6].str);
96                 url.query = m[8].str;
97                 url.fragment = m[10].str;
98                 return url;
99         }
100         else
101                 throw InvalidParameterValue("Invalid URL");
102 }
103
104 string build_url(const Url &url)
105 {
106         if(!url.path.empty() && url.path[0]!='/')
107                 throw InvalidParameterValue("Only absolute paths are supported");
108         string str;
109         if(!url.scheme.empty())
110                 str += url.scheme+"://";
111         str += url.host;
112         str += urlencode(url.path);
113         if(!url.query.empty())
114         {
115                 str += '?';
116                 str += url.query;
117         }
118         if(!url.fragment.empty())
119         {
120                 str += '#';
121                 str += url.fragment;
122         }
123         return str;
124 }
125
126 Query parse_query(const std::string &str)
127 {
128         vector<string> parts = split(str, '&');
129         Query query;
130         for(vector<string>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
131         {
132                 unsigned equals = i->find('=');
133                 string &value = query[urldecode(i->substr(0, equals))];
134                 if(equals!=string::npos)
135                         value = urldecode(i->substr(equals+1));
136         }
137         return query;
138 }
139
140 string build_query(const Query &query)
141 {
142         string str;
143         for(Query::const_iterator i=query.begin(); i!=query.end(); ++i)
144         {
145                 if(i!=query.begin())
146                         str += '&';
147                 str += urlencode_plus(i->first);
148                 str += '=';
149                 str += urlencode_plus(i->second);
150         }
151         return str;
152 }
153
154 } // namespace Http
155 } // namespace Msp