URL-Handling: de-Url-Escapify username and Passwords.
[citadel.git] / libcitadel / lib / urlhandling.c
1 #include "sysdep.h"
2 #include <ctype.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <sys/select.h>
9 #include <fcntl.h>
10 #include <sys/types.h>
11 #include "libcitadel.h"
12 #include <sys/socket.h>
13
14 /**
15  * @defgroup URLHandling ParsedURL object to handle connection data
16  */
17
18 /**
19  * @ingroup URLHandling
20  * @brief frees a linked list of ParsedURL 
21  * @param Url (list) of ParsedURL to be freet; Pointer is NULL'ed for the caller.
22  */
23 void FreeURL(ParsedURL** Url)
24 {
25         if (*Url != NULL) {
26                 FreeStrBuf(&(*Url)->URL);
27                 FreeStrBuf(&(*Url)->UrlWithoutCred);
28                 FreeStrBuf(&(*Url)->CurlCreds);
29                 FreeStrBuf(&(*Url)->UsrName);
30                 FreeStrBuf(&(*Url)->Password);
31                 if ((*Url)->Next != NULL)
32                         FreeURL(&(*Url)->Next);
33                 free(*Url);
34                 *Url = NULL;
35         }
36 }
37
38 /**
39  * @ingroup URLHandling
40  * @brief parses the string provided with UrlStr into *Url
41  * @param Url on success this contains the parsed object; needs to be free'd by caller.
42  * @param UrlStr String we should parse into parts
43  * @param DefaultPort Which is the default port here?
44  */
45 int ParseURL(ParsedURL **Url, StrBuf *UrlStr, unsigned short DefaultPort)
46 {
47         const char *pch, *pEndHost, *pPort, *pCredEnd, *pUserEnd;
48         ParsedURL *url = (ParsedURL *)malloc(sizeof(ParsedURL));
49         memset(url, 0, sizeof(ParsedURL));
50
51         url->af = AF_INET;
52         url->Port =  DefaultPort;
53         /*
54          * http://username:passvoid@[ipv6]:port/url 
55          */
56         url->URL = NewStrBufDup(UrlStr);
57         url->Host = pch = ChrPtr(url->URL);
58         pEndHost = url->LocalPart = strchr(pch, '/');
59         if (url->LocalPart != NULL) {
60                 if ((*(url->LocalPart + 1) == '/') && 
61                     (*(url->LocalPart - 1) == ':')) { /* TODO: find default port for this protocol... */
62                         url->Host = url->LocalPart + 2;
63                         pEndHost = url->LocalPart = strchr(url->Host, '/');
64                         if (url->LocalPart != NULL)
65                         {
66                             StrBufPeek(url->URL, url->LocalPart, 0, '\0');
67                             url->LocalPart++;
68                         }
69                 }
70         }
71         if (url->LocalPart == NULL) {
72                 pEndHost = url->LocalPart = ChrPtr(url->URL) + StrLength(url->URL);
73         }
74
75         pCredEnd = strrchr(ChrPtr(url->URL), '@');
76         if (pCredEnd >= url->LocalPart)
77                 pCredEnd = NULL;
78         if (pCredEnd != NULL)
79         {
80                 url->User = url->Host;
81                 url->Host = pCredEnd + 1;
82                 pUserEnd = strchr(url->User, ':');
83                 
84                 if (pUserEnd > pCredEnd)
85                         pUserEnd = pCredEnd;
86                 else {
87                         url->Pass = pUserEnd + 1;
88                 }
89                 StrBufPeek(url->URL, pUserEnd, 0, '\0');
90                 StrBufPeek(url->URL, pCredEnd, 0, '\0');                
91         }
92         
93         pPort = NULL;
94         if (*url->Host == '[') {
95                 url->Host ++;
96                 pEndHost = strchr(url->Host, ']');
97                 if (pEndHost == NULL) {
98                         FreeStrBuf(&url->URL);
99                         free(url);
100                         return 0; /* invalid syntax, no ipv6 */
101                 }
102                 StrBufPeek(url->URL, pEndHost, 0, '\0');
103                 if (*(pEndHost + 1) == ':'){
104                         StrBufPeek(url->URL, pEndHost + 1, 0, '\0');
105                         pPort = pEndHost + 2;
106                 }
107                 url->af = AF_INET6;
108         }
109         else {
110                 pPort = strchr(url->Host, ':');
111                 if (pPort != NULL) {
112                         StrBufPeek(url->URL, pPort, 0, '\0');
113                         pPort ++;
114                 }
115         }
116         if (pPort != NULL)
117                 url->Port = atol(pPort);
118         if (url->IPv6)
119         {
120             url->IsIP = inet_pton(AF_INET6, url->Host, &url->Addr.sin6_addr);
121             if (url->IsIP)
122             {
123                 url->Addr.sin6_port = htons(url->Port);
124                 url->Addr.sin6_port = AF_INET6;
125             }
126         }
127         else
128         {
129             url->IsIP = inet_pton(AF_INET, url->Host, &((struct sockaddr_in *)&(url->Addr))->sin_addr);
130             if (url->IsIP)
131             {
132                 ((struct sockaddr_in *)&(url->Addr))->sin_port = htons(url->Port);
133                 ((struct sockaddr_in *)&(url->Addr))->sin_family = AF_INET;
134             }   
135         }
136
137         if (url->User != NULL) {
138                 url->UsrName = NewStrBufPlain(url->User, pUserEnd - url->User);
139                 StrBufUnescape(url->UsrName, 0);
140                 url->User = ChrPtr(url->UsrName);
141         }
142
143         if (url->Pass != NULL) {
144                 url->Password = NewStrBufPlain(url->Pass, pCredEnd - url->Pass);
145                 StrBufUnescape(url->Password, 0);
146                 url->Pass = ChrPtr(url->Password);
147         }
148
149         if (*Url != NULL)
150                 url->Next = *Url;
151         *Url = url;
152         return 1;
153 }
154
155 void CurlPrepareURL(ParsedURL *Url)
156 {
157         if (!strcmp(ChrPtr(Url->URL), "http"))
158                 Url->UrlWithoutCred = NewStrBufPlain(ChrPtr(Url->URL), -1);
159         else 
160                 Url->UrlWithoutCred = NewStrBufPlain(HKEY("http://"));
161         StrBufAppendBufPlain(Url->UrlWithoutCred, Url->Host, -1, 0);
162
163         StrBufAppendBufPlain(Url->UrlWithoutCred, HKEY(":"), 0);
164
165         StrBufAppendPrintf(Url->UrlWithoutCred, "%u", Url->Port);
166
167         StrBufAppendBufPlain(Url->UrlWithoutCred, HKEY("/"), 0);
168         if (Url->LocalPart)
169         {
170             StrBufAppendBufPlain(Url->UrlWithoutCred, Url->LocalPart, -1, 0);
171         }
172         if (Url->User != NULL)
173         {
174                 Url->CurlCreds = NewStrBufPlain(Url->User, -1);
175                 StrBufAppendBufPlain(Url->CurlCreds, HKEY(":"), 0);
176                 if (Url->Pass != NULL)
177                         StrBufAppendBufPlain(Url->CurlCreds, Url->Pass, -1, 0);
178         }
179         Url->PlainUrl = ChrPtr(Url->UrlWithoutCred);
180 }