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