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