817338426d4ee2490399d7686178a2aaf78f84c5
[oweals/gnunet.git] / src / transport / plugin_transport_http_common.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/plugin_transport_http_common.c
23  * @brief functionality shared by http client and server transport service plugin
24  * @author Matthias Wachs
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_transport_plugin.h"
30 #include "plugin_transport_http_common.h"
31
32 struct SplittedHTTPAddress
33 {
34         char *protocol;
35         char *host;
36         char *path;
37         int port;
38 };
39
40 struct SplittedHTTPAddress *
41 http_split_address (const char * addr)
42 {
43         struct SplittedHTTPAddress  *sp;
44         char *src = GNUNET_strdup (addr);
45         char *protocol_start = NULL;
46         char *host_start = NULL;
47         char *v6_end = NULL;
48         char *port_start = NULL;
49         char *path_start = NULL;
50
51         protocol_start = src;
52         sp = GNUNET_malloc (sizeof (struct SplittedHTTPAddress));
53
54         /* Address string consists of protocol://host[:port]path*/
55
56         host_start = strstr (src, "://");
57         if (NULL == host_start)
58         {
59                         GNUNET_free (src);
60                         GNUNET_free (sp);
61                         return NULL;
62         }
63
64         host_start[0] = '\0';
65         sp->protocol = GNUNET_strdup (protocol_start);
66
67         host_start += strlen ("://");
68         if (strlen (host_start) == 0)
69         {
70                         GNUNET_free (src);
71                         GNUNET_free (sp->protocol);
72                         GNUNET_free (sp);
73                         return NULL;
74         }
75
76         /* Find path start */
77         path_start = strchr (host_start, '/');
78         if (NULL != path_start)
79         {
80                         sp->path = GNUNET_strdup (path_start);
81                         path_start[0] = '\0';
82         }
83         else
84                 sp->path = GNUNET_strdup ("");
85
86         if (strlen(host_start) < 1)
87         {
88                         GNUNET_free (src);
89                         GNUNET_free (sp->protocol);
90                         GNUNET_free (sp->path);
91                         GNUNET_free (sp);
92                         return NULL;
93         }
94
95         if (NULL != (port_start = strrchr (host_start, ':')))
96         {
97                         /* *We COULD have a port, but also an IPv6 address! */
98                         if (NULL != (v6_end = strchr(host_start, ']')))
99                         {
100                                         if  (v6_end < port_start)
101                                         {
102                                                         /* IPv6 address + port */
103                                                         port_start[0] = '\0';
104                                                         port_start ++;
105                                                         sp->port = atoi (port_start);
106                                         }
107                                         else
108                                         {
109                                                         /* IPv6 address + no port */
110                                                         if (0 == strcmp(sp->protocol, "https"))
111                                                                 sp->port = HTTPS_DEFAULT_PORT;
112                                                         else if (0 == strcmp(sp->protocol, "http"))
113                                                                 sp->port = HTTP_DEFAULT_PORT;
114                                         }
115                         }
116                         else
117                         {
118                                         /* No IPv6 address */
119                                         port_start[0] = '\0';
120                                         port_start ++;
121                                         sp->port = atoi (port_start);
122                         }
123         }
124         else
125         {
126                 /* No ':' as port separator, default port for protocol */
127                 if (0 == strcmp(sp->protocol, "https"))
128                         sp->port = HTTPS_DEFAULT_PORT;
129                 else if (0 == strcmp(sp->protocol, "http"))
130                         sp->port = HTTP_DEFAULT_PORT;
131                 else
132                 {
133                                 GNUNET_break (0);
134                                 GNUNET_free (src);
135                                 GNUNET_free (sp->protocol);
136                                 GNUNET_free (sp->path);
137                                 GNUNET_free (sp);
138                                 return NULL;
139                 }
140         }
141         if (strlen (host_start) > 0)
142                         sp->host = GNUNET_strdup (host_start);
143         else
144         {
145                         GNUNET_break (0);
146                         GNUNET_free (src);
147                         GNUNET_free (sp->protocol);
148                         GNUNET_free (sp->path);
149                         GNUNET_free (sp);
150                         return NULL;
151         }
152         GNUNET_free (src);
153         //fprintf (stderr, "addr: `%s' protocol: `%s', host `%s' port `%u' path `%s'\n", addr, sp->protocol, sp->host, sp->port, sp->path);
154         return sp;
155 }
156
157 /**
158  * Convert the transports address to a nice, human-readable
159  * format.
160  *
161  * @param cls closure
162  * @param type name of the transport that generated the address
163  * @param addr one of the addresses of the host, NULL for the last address
164  *        the specific address format depends on the transport
165  * @param addrlen length of the address
166  * @param numeric should (IP) addresses be displayed in numeric form?
167  * @param timeout after how long should we give up?
168  * @param asc function to call on each string
169  * @param asc_cls closure for asc
170  */
171 void
172 http_common_plugin_address_pretty_printer (void *cls, const char *type,
173                                         const void *addr, size_t addrlen,
174                                         int numeric,
175                                         struct GNUNET_TIME_Relative timeout,
176                                         GNUNET_TRANSPORT_AddressStringCallback
177                                         asc, void *asc_cls)
178 {
179   const char *saddr = (const char *) addr;
180
181   if ( (NULL == saddr) ||
182        (0 >= addrlen) ||
183        ('\0' != saddr[addrlen-1]) )
184   {
185       asc (asc_cls, NULL);
186       return;
187   }
188   asc (asc_cls, saddr);
189   asc (asc_cls, NULL);
190 }
191
192
193 /**
194  * Function called for a quick conversion of the binary address to
195  * a numeric address.  Note that the caller must not free the
196  * address and that the next call to this function is allowed
197  * to override the address again.
198  *
199  * @param cls closure
200  * @param addr binary address
201  * @param addrlen length of the address
202  * @return string representing the same address
203  */
204 const char *
205 http_common_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
206 {
207   const char *saddr = (const char *) addr;
208   if (NULL == saddr)
209       return NULL;
210   if (0 >= addrlen)
211     return NULL;
212   if (saddr[addrlen-1] != '\0')
213     return NULL;
214   return saddr;
215 }
216
217 /**
218  * Function called to convert a string address to
219  * a binary address.
220  *
221  * @param cls closure ('struct Plugin*')
222  * @param addr string address
223  * @param addrlen length of the address
224  * @param buf location to store the buffer
225  *        If the function returns GNUNET_SYSERR, its contents are undefined.
226  * @param added length of created address
227  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
228  */
229 int
230 http_common_plugin_string_to_address (void *cls,
231                         const char *addr,
232                         uint16_t addrlen,
233                         void **buf,
234                         size_t *added)
235 {
236   if (NULL == addr)
237       return GNUNET_SYSERR;
238   if (0 >= addrlen)
239     return GNUNET_SYSERR;
240   if (addr[addrlen-1] != '\0')
241     return GNUNET_SYSERR;
242
243   (*buf) = strdup (addr);
244   (*added) = strlen (addr) + 1;
245   return GNUNET_OK;
246 }
247
248 /**
249  * Create a HTTP address from a socketaddr
250  *
251  * @param protocol protocol
252  * @param addr sockaddr * address
253  * @param addrlen length of the address
254  * @return the string
255  */
256 char *
257 http_common_address_from_socket (const char *protocol, const struct sockaddr *addr, socklen_t addrlen)
258 {
259   char *res;
260   GNUNET_asprintf(&res, "%s://%s", protocol, GNUNET_a2s (addr, addrlen));
261   return res;
262 }
263
264 /**
265  * Create a socketaddr from a HTTP address
266  *
267  * @param addr sockaddr * address
268  * @param addrlen length of the address
269  * @param res the result:
270  * GNUNET_SYSERR, invalid input,
271  * GNUNET_YES: could convert to ip,
272  * GNUNET_NO: valid input but could not convert to ip (hostname?)
273  * @return the string
274  */
275 struct sockaddr *
276 http_common_socket_from_address (const void *addr, size_t addrlen, int *res)
277 {
278   struct sockaddr_storage *s;
279   char *addrs;
280   char *addrs_org;
281   char *addrs_end;
282   (*res) = GNUNET_SYSERR;
283
284   if (NULL == addr)
285     {
286       GNUNET_break (0);
287       return NULL;
288     }
289   if (0 >= addrlen)
290     {
291       GNUNET_break (0);
292       return NULL;
293     }
294   if (((char *) addr)[addrlen-1] != '\0')
295     {
296       GNUNET_break (0);
297       return NULL;
298     }
299
300   addrs_org = strdup ((char *) addr);
301   addrs = strstr (addrs_org , "://");
302   if (NULL == addrs)
303   {
304     GNUNET_break (0);
305     GNUNET_free (addrs_org);
306     return NULL;
307   }
308
309   if (strlen (addrs) < 3)
310   {
311     GNUNET_break (0);
312     GNUNET_free (addrs_org);
313     return NULL;
314   }
315
316   addrs += 3;
317
318   addrs_end = strchr (addrs, '/');
319   if (NULL != addrs_end)
320     addrs[strlen (addrs) - strlen(addrs_end)] = '\0';
321
322   s = GNUNET_malloc (sizeof (struct sockaddr_storage));
323   if (GNUNET_SYSERR == GNUNET_STRINGS_to_address_ip (addrs, strlen(addrs), s))
324   {
325     /* could be a hostname */
326     GNUNET_free (s);
327     GNUNET_free (addrs_org);
328     (*res) = GNUNET_NO;
329     return NULL;
330   }
331   else
332   {
333     if ((AF_INET != s->ss_family) && (AF_INET6 != s->ss_family))
334     {
335       GNUNET_break (0);
336       GNUNET_free (s);
337       GNUNET_free (addrs_org);
338       (*res) = GNUNET_SYSERR;
339       return NULL;
340     }
341   }
342   (*res) = GNUNET_YES;
343   GNUNET_free (addrs_org);
344   return (struct sockaddr *) s;
345 }
346
347 /**
348  * Get the length of an address
349  *
350  * @param addr address
351  * @return the size
352  */
353 size_t
354 http_common_address_get_size (const void *addr)
355 {
356  return strlen (addr) + 1;
357 }
358
359 /**
360  * Compare addr1 to addr2
361  *
362  * @param addr1 address1
363  * @param addrlen1 address 1 length
364  * @param addr2 address2
365  * @param addrlen2 address 2 length
366  * @return GNUNET_YES if equal, GNUNET_NO if not, GNUNET_SYSERR on error
367  */
368 size_t
369 http_common_cmp_addresses (const void *addr1, size_t addrlen1, const void *addr2, size_t addrlen2)
370 {
371   const char *a1 = (const char *) addr1;
372   const char *a2 = (const char *) addr2;
373
374   if (NULL == a1)
375       return GNUNET_SYSERR;
376   if (0 >= addrlen1)
377     return GNUNET_SYSERR;
378   if (a1[addrlen1-1] != '\0')
379     return GNUNET_SYSERR;
380
381   if (NULL == a2)
382       return GNUNET_SYSERR;
383   if (0 >= addrlen2)
384     return GNUNET_SYSERR;
385   if (a2[addrlen2-1] != '\0')
386     return GNUNET_SYSERR;
387
388   if (addrlen1 != addrlen2)
389     return GNUNET_NO;
390
391   if (0 == strcmp (addr1, addr2))
392     return GNUNET_YES;
393   return GNUNET_NO;
394 }
395
396
397
398 /* end of plugin_transport_http_common.c */