/[winpt]/trunk/Src/wptHTTP.c
ViewVC logotype

Annotation of /trunk/Src/wptHTTP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 13159 byte(s)
WinPT initial checkin.


1 twoaday 2 /* wptHTTP.c - HTTP support
2     * Copyright (C) 2004 Timo Schulz
3     *
4     * This file is part of WinPT.
5     *
6     * WinPT is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU General Public License
8     * as published by the Free Software Foundation; either version 2
9     * of the License, or (at your option) any later version.
10     *
11     * WinPT is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with WinPT; if not, write to the Free Software Foundation,
18     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <stdio.h>
22     #include <stdlib.h>
23     #include <string.h>
24     #ifdef _WIN32
25     #include <windows.h>
26     #else
27     #include <unistd.h>
28     #include <netdb.h>
29     #include <netinet/in.h>
30     #include <sys/socket.h>
31     #include <arpa/inet.h>
32     #include <sys/time.h>
33     #endif
34     #include <ctype.h>
35     #include <errno.h>
36    
37    
38     #include "wptHTTP.h"
39    
40    
41     static int parse_headers (int fd, http_head_t * r_head);
42    
43    
44     static int
45     http_head_new (http_head_t * head, const char * val)
46     {
47     http_head_t h;
48    
49     h = calloc (1, sizeof * h + strlen (val) + 1);
50     if (h == NULL)
51     abort ();
52     strcpy (h->d, val);
53     *head = h;
54     return 0;
55     }
56    
57    
58     static void
59     http_head_free (http_head_t head)
60     {
61     http_head_t h;
62    
63     while (head)
64     {
65     h = head->next;
66     free (head);
67     head = h;
68     }
69     }
70    
71    
72     static void
73     http_head_add (http_head_t root, http_head_t node)
74     {
75     http_head_t n;
76    
77     for (n = root; n->next; n=n->next)
78     ;
79     n->next = node;
80     }
81    
82    
83     static http_head_t
84     http_head_find (http_head_t root, const char * name,
85     const char ** val)
86     {
87     http_head_t n;
88    
89     for (n = root; n; n = n->next)
90     {
91     if (strlen (n->d) >= strlen (name) &&
92     !strncmp (n->d, name, strlen (name)))
93     {
94     *val = n->d + strlen (name);
95     return n;
96     }
97     }
98     return NULL;
99     }
100    
101    
102     static int
103     http_connect (const char * host, int port, int * r_fd)
104     {
105     struct hostent * hp;
106     struct sockaddr_in srv;
107     unsigned long addr = 0;
108     int i = 1;
109     int fd;
110    
111     if (r_fd)
112     *r_fd = 0;
113     memset (&srv, 0, sizeof srv);
114     srv.sin_port = htons ((unsigned short)port);
115     srv.sin_family = AF_INET;
116    
117     if (isalpha (*host))
118     {
119     hp = gethostbyname (host);
120     if (hp == NULL)
121     {
122     fprintf (stderr, "** gethostbyname(): %s\n", strerror (errno));
123     return HTTP_ERR_CONNECT;
124     }
125     memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);
126     }
127     else
128     {
129     addr = inet_addr (host);
130     if (addr == -1)
131     {
132     fprintf (stderr, "** inet_addr(): %s\n", strerror (errno));
133     return HTTP_ERR_INVADDR;
134     }
135     memcpy (&srv.sin_addr, &addr, sizeof addr);
136     }
137    
138     fd = socket (AF_INET, SOCK_STREAM, 0);
139     if (fd < 0)
140     {
141     fprintf (stderr, "** socket(): %s\n", strerror (errno));
142     return HTTP_ERR_SOCK;
143     }
144    
145     if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&i, sizeof i))
146     return HTTP_ERR_SOCK;
147    
148     if (connect (fd, (struct sockaddr *)&srv, sizeof srv))
149     {
150     s_close (fd);
151     fprintf (stderr, "** connect(): %s\n", strerror (errno));
152     return HTTP_ERR_CONNECT;
153     }
154     if (r_fd)
155     *r_fd = fd;
156     else
157     s_close (fd);
158     return 0;
159     }
160    
161    
162     static int
163     http_close (int fd)
164     {
165     s_close (fd);
166     return 0;
167     }
168    
169    
170     static int
171     http_data_avail (int fd)
172     {
173     struct timeval tv;
174     fd_set inp;
175     int n;
176    
177     FD_ZERO (&inp);
178     FD_SET (fd, &inp);
179     tv.tv_sec = 1;
180     tv.tv_usec = 0;
181    
182     n = select (fd+1, &inp, NULL, NULL, &tv);
183     if (n && FD_ISSET (fd, &inp))
184     return n;
185     return 0;
186     }
187    
188    
189     static int
190     http_read_line (int fd, char * buf, size_t nbuf,
191     int nonblock, int * nn, int * eof)
192     {
193     char c;
194     int n, i;
195    
196     if (nn)
197     *nn = 0;
198     if (eof)
199     *eof = 0;
200     i = 0;
201     do
202     {
203     if (nonblock == 1 && http_data_avail (fd) == 0)
204     {
205     fprintf (stderr, "** fd timeout.\n");
206     buf[i++] = '\0';
207     i = -1;
208     break;
209     }
210     n = recv (fd, &c, 1, 0);
211     if (n == -1)
212     break;
213     if (n == 0 || nbuf == 0 || c == '\n')
214     {
215     if (n == 0)
216     {
217     /*fprintf (stderr, "** fd eof (%d).\n", i);*/
218     if (eof)
219     *eof = 1;
220     buf[i++] = '\0';
221     }
222     else
223     {
224     buf[i++] = c;
225     buf[i] = '\0';
226     }
227     break;
228     }
229     else
230     {
231     buf[i++] = c;
232     nbuf--;
233     }
234     } while (n > 0 && i != -1);
235    
236     if (nn)
237     *nn = i;
238     return 0;
239     }
240    
241    
242     static int
243     http_send_req (int fd, const char * host, const char * url)
244     {
245     char * p;
246     int n;
247    
248     if (*url == '/')
249     url++;
250     if (url == NULL)
251     url = "";
252     p = malloc (strlen (url) + strlen (host) + 64);
253     if (p == NULL)
254     abort ();
255     sprintf (p, "GET /%s HTTP/1.1\r\n"
256     "Host: %s\r\n"
257     "\r\n"
258     "\r\n",
259     url, host);
260     n = send (fd, p, strlen (p), 0);
261     free (p);
262     if (n == -1)
263     {
264     fprintf (stderr, "** send(): %s\n", strerror (errno));
265     return HTTP_ERR_IO;
266     }
267     return 0;
268     }
269    
270    
271     int
272     http_send_request2 (const char * url, http_hd_t * r_hd)
273     {
274     http_hd_t hd;
275     char * host = NULL, * p;
276     char tmpbuf[512];
277     int rc;
278    
279     memset (tmpbuf, 0, 512);
280     strncpy (tmpbuf, url, 512);
281    
282     if (strlen (url) < 10 || strncmp (url, "http://", 7))
283     return HTTP_ERR_PROTO;
284     url += 7;
285     p = strtok (tmpbuf+7, "/");
286     if (p == NULL)
287     return HTTP_ERR_PROTO;
288     host = strdup (p);
289     if (host == NULL)
290     abort ();
291     p = strchr (url, '/');
292     if (p == NULL)
293     {
294     free (host);
295     return HTTP_ERR_PROTO;
296     }
297     rc = http_send_request (host, 80, p+1, &hd);
298     if (r_hd)
299     *r_hd = hd;
300     else
301     http_hd_free (hd);
302     free (host);
303     return rc;
304     }
305    
306    
307     int
308     http_send_request (const char * host, int port, const char * url,
309     http_hd_t * r_hd)
310     {
311     http_hd_t hd;
312     int rc;
313    
314     http_hd_new (&hd);
315     rc = http_connect (host, port, &hd->fd);
316     if (!rc)
317     rc = http_send_req (hd->fd, host, url);
318     if (r_hd)
319     *r_hd = hd;
320     else
321     http_hd_free (hd);
322     return rc;
323     }
324    
325    
326     int
327     http_req_new (http_req_t * ctx)
328     {
329     http_req_t c;
330     c = calloc (1, sizeof * c);
331     if (c == NULL)
332     abort ();
333     *ctx = c;
334     return 0;
335     }
336    
337    
338     void
339     http_req_free (http_req_t ctx)
340     {
341     if (!ctx)
342     return;
343     http_head_free (ctx->head);
344     if (ctx->url)
345     free (ctx->url);
346     free (ctx);
347     }
348    
349    
350     static int
351     parse_reqline (const char * buf, http_req_t * ctx)
352     {
353     http_req_t c;
354     char * p;
355     int pos = 0;
356    
357     *ctx = NULL;
358     http_req_new (&c);
359     if (strlen (buf) < 4)
360     return HTTP_ERR_PROTO;
361     if (!strncmp (buf, "GET", 3))
362     {
363     c->type = HTTP_GET;
364     buf += 3;
365     }
366     else if (!strncmp (buf, "POST", 4))
367     {
368     c->type = HTTP_POST;
369     buf += 4;
370     }
371     else
372     {
373     http_req_free (c);
374     return HTTP_ERR_PROTO;
375     }
376     buf++;
377     p = strchr (buf, ' ');
378     if (p == NULL)
379     {
380     http_req_free (c);
381     return HTTP_ERR_PROTO;
382     }
383     c->url = malloc (p-buf+2);
384     if (c->url == NULL)
385     abort ();
386     while (*buf != ' ')
387     c->url[pos++] = *buf++;
388     c->url[pos] = '\0';
389     buf++;
390     if (strncmp (buf, "HTTP/1.", 7))
391     {
392     http_req_free (c);
393     return HTTP_ERR_PROTO;
394     }
395     *ctx = c;
396     return 0;
397     }
398    
399    
400     int
401     http_parse_request (http_hd_t hd, http_req_t * r_req)
402     {
403     http_req_t req;
404     char buf[1024+1];
405     int rc, n;
406    
407     rc = http_read_line (hd->fd, buf, 1024, 0, &n, NULL);
408     if (rc)
409     return rc;
410     rc = parse_reqline (buf, &req);
411     if (rc)
412     return rc;
413     rc = parse_headers (hd->fd, &hd->head);
414     if (rc)
415     {
416     http_req_free (req);
417     return rc;
418     }
419     *r_req = req;
420     return 0;
421     }
422    
423    
424     static int
425     parse_statline (const char * buf, int * code)
426     {
427     int tmp = 0;
428    
429     if (strlen (buf) < 8 ||
430     (strncmp (buf, "HTTP/1.", 7)))
431     {
432     fprintf (stderr, "** invalid proto: '%s'\n", buf);
433     return HTTP_ERR_PROTO;
434     }
435     buf += 8; /* skip HTTP/1.x */
436     buf++; /* white space */
437     tmp = atoi (buf);
438     if (tmp == 0)
439     {
440     fprintf (stderr, "** invalid statcode: %s\n", buf);
441     return HTTP_ERR_PROTO;
442     }
443     *code = tmp;
444     buf += 3;
445     buf++; /* whitespace */
446     return 0;
447     }
448    
449    
450     static int
451     parse_headers (int fd, http_head_t * r_head)
452     {
453     http_head_t h, head = NULL;
454     char buf[300];
455     int nn;
456     int rc;
457    
458     do
459     {
460     rc = http_read_line (fd, buf, 299, 1, &nn, NULL);
461     if (rc)
462     return rc;
463     if (nn == 2)
464     break; /* reach empty line */
465     http_head_new (&h, buf);
466     if (head == NULL)
467     head = h;
468     else
469     http_head_add (head, h);
470     } while (rc == 0);
471     if (r_head)
472     *r_head = head;
473     else
474     http_head_free (head);
475     return 0;
476     }
477    
478    
479     static int
480     read_binary (int fd, int nlen, FILE * out)
481     {
482     char buf[1024+1];
483     int n;
484    
485     do
486     {
487     n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);
488     if (n == -1)
489     {
490     fprintf (stderr, "** recv(): %s\n", strerror (errno));
491     return HTTP_ERR_IO;
492     }
493     if (n == 0)
494     break;
495     nlen -= n;
496     fwrite (buf, 1, n, out);
497     } while (nlen > 0);
498     return 0;
499     }
500    
501    
502     static int
503     parse_data (int fd, http_head_t head, FILE * out)
504     {
505     http_head_t h;
506     const char * s = "Content-Length: ", * val;
507     char buf[1024+1];
508     int nlen = 0, nn = 0, n, eof=0;
509     int rc;
510    
511     h = http_head_find (head, s, &val);
512     if (h)
513     nlen = atoi (val);
514     else
515     {
516     h = http_head_find (head, "Connection: ", &val);
517     if (h == NULL || strncmp (val, "close", 4))
518     return HTTP_ERR_PROTO;
519     }
520    
521     h = http_head_find (head, "Content-Type: ", &val);
522     if (h == NULL)
523     return HTTP_ERR_PROTO;
524     if (strncmp (val, "text", 4))
525     return read_binary (fd, nlen, out);
526    
527     do
528     {
529     rc = http_read_line (fd, buf, 1024, 1, &n, &eof);
530     if (rc)
531     return rc;
532     if (n > 0)
533     fwrite (buf, 1, n, out);
534     if (nlen > 0)
535     {
536     nn += n;
537     if (nlen == nn)
538     break;
539     }
540     } while (eof == 0);
541     return 0;
542     }
543    
544    
545     static int
546     check_status (int code, int * statcode)
547     {
548     if (code != HTTP_STAT_200)
549     {
550     fprintf (stderr, "** problem with response status=%d\n", code);
551     if (statcode)
552     *statcode = code;
553     if (code == HTTP_STAT_400 ||
554     code == HTTP_STAT_403 ||
555     code == HTTP_STAT_404 ||
556     code == HTTP_STAT_405)
557     return HTTP_ERR_STAT;
558     }
559     return 0;
560     }
561    
562    
563     int
564     http_parse_response (http_hd_t hd, int * statcode)
565     {
566     char buf[300];
567     int rc;
568     int code = 0, nn = 0;
569    
570     if (statcode)
571     *statcode = 0;
572     rc = http_read_line (hd->fd, buf, 299, 1, &nn, NULL);
573     if (rc)
574     return rc;
575     rc = parse_statline (buf, &code);
576     if (rc)
577     return rc;
578     rc = check_status (code, statcode);
579     if (rc)
580     return rc;
581     rc = parse_headers (hd->fd, &hd->head);
582     if (rc)
583     return rc;
584     {
585     http_head_t t;
586     fprintf (stderr, "HTTP headers: \n");
587     for (t = hd->head; t; t=t->next)
588     fprintf (stderr, "%s", t->d);
589     fprintf (stderr, "\n");
590     }
591     return 0;
592     }
593    
594    
595     int
596     http_parse_data (http_hd_t hd, FILE * out)
597     {
598     int rc = 0;
599    
600     rc = parse_data (hd->fd, hd->head, out);
601    
602     http_close (hd->fd);
603    
604     return rc;
605     }
606    
607    
608     const char *
609     http_strerror (int rc)
610     {
611     switch (rc)
612     {
613     case HTTP_ERR_SUCCESS: return "operation successfull";
614     case HTTP_ERR_CONNECT: return "could not connect to host";
615     case HTTP_ERR_INVADDR: return "invalid address";
616     case HTTP_ERR_SOCK: return "socket error";
617     case HTTP_ERR_IO: return "input/output error";
618     case HTTP_ERR_PROTO: return "protocol violation";
619     case HTTP_ERR_STAT: return "status code indicates an error";
620     default: return "unknown error";
621     }
622     return NULL;
623     }
624    
625    
626     int
627     http_hd_new (http_hd_t * r_hd)
628     {
629     http_hd_t hd;
630    
631     if (!r_hd)
632     return -1;
633     hd = calloc (1, sizeof * hd);
634     if (hd == NULL)
635     abort ();
636     *r_hd = hd;
637     return 0;
638     }
639    
640    
641     void
642     http_hd_free (http_hd_t hd)
643     {
644     if (!hd)
645     return;
646     http_head_free (hd->head);
647     http_close (hd->fd);
648     free (hd);
649     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26