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

Annotation of /trunk/Src/wptHTTP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (hide annotations)
Thu Oct 27 15:25:13 2005 UTC (19 years, 4 months ago) by werner
File MIME type: text/plain
File size: 9407 byte(s)
First set of changes to use autotools for building.
1 werner 36 /* wptHTTP.c - Generic HTTP support
2     * Copyright (C) 2004, 2005 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     #ifdef HAVE_CONFIG_H
21     #include <config.h>
22     #endif
23    
24     #include <stdio.h>
25     #include <stdio.h>
26     #include <stdlib.h>
27     #include <string.h>
28     #include <windows.h>
29     #include <ctype.h>
30     #include <errno.h>
31    
32     #include "wptHTTP.h"
33     #include "wptTypes.h"
34     #include "wptErrors.h"
35    
36    
37     static int parse_headers (int fd, http_head_t *r_head);
38    
39    
40     static int
41     http_head_new (http_head_t * head, const char * val)
42     {
43     http_head_t h;
44    
45     h = calloc (1, sizeof *h + strlen (val) + 1);
46     if (!h)
47     BUG (0);
48     strcpy (h->d, val);
49     *head = h;
50     return 0;
51     }
52    
53    
54     static void
55     http_head_free (http_head_t head)
56     {
57     http_head_t h;
58    
59     while (head) {
60     h = head->next;
61     free (head);
62     head = h;
63     }
64     }
65    
66    
67     static void
68     http_head_add (http_head_t root, http_head_t node)
69     {
70     http_head_t n;
71    
72     for (n = root; n->next; n=n->next)
73     ;
74     n->next = node;
75     }
76    
77    
78     static http_head_t
79     http_head_find (http_head_t root, const char * name,
80     const char ** val)
81     {
82     http_head_t n;
83    
84     for (n = root; n; n = n->next) {
85     if (strlen (n->d) >= strlen (name) &&
86     !strncmp (n->d, name, strlen (name))) {
87     *val = n->d + strlen (name);
88     return n;
89     }
90     }
91     return NULL;
92     }
93    
94    
95     static int
96     http_connect (const char * host, int port, int * r_fd)
97     {
98     struct hostent * hp;
99     struct sockaddr_in srv;
100     unsigned long addr = 0;
101     int i = 1;
102     int fd;
103    
104     *r_fd = 0;
105     memset (&srv, 0, sizeof srv);
106     srv.sin_port = htons ((unsigned short)port);
107     srv.sin_family = AF_INET;
108    
109     if (isalpha (*host)) {
110     hp = gethostbyname (host);
111     if (hp == NULL)
112     return WPTERR_WINSOCK_CONNECT;
113     memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);
114     }
115     else {
116     addr = inet_addr (host);
117     if (addr == -1)
118     return WPTERR_WINSOCK_CONNECT;
119     memcpy (&srv.sin_addr, &addr, sizeof addr);
120     }
121    
122     fd = socket (AF_INET, SOCK_STREAM, 0);
123     if (fd < 0)
124     return WPTERR_WINSOCK_SOCKET;
125    
126     if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&i, sizeof i)) {
127     closesocket (fd);
128     return WPTERR_WINSOCK_SOCKET;
129     }
130    
131     if (connect (fd, (struct sockaddr *)&srv, sizeof srv)) {
132     closesocket (fd);
133     return WPTERR_WINSOCK_CONNECT;
134     }
135    
136     *r_fd = fd;
137     return 0;
138     }
139    
140    
141     static int
142     http_close (int fd)
143     {
144     closesocket (fd);
145     return 0;
146     }
147    
148    
149     static int
150     http_data_avail (int fd)
151     {
152     struct timeval tv;
153     fd_set inp;
154     int n;
155    
156     FD_ZERO (&inp);
157     FD_SET (fd, &inp);
158     tv.tv_sec = 1;
159     tv.tv_usec = 0;
160    
161     n = select (fd+1, &inp, NULL, NULL, &tv);
162     if (n && FD_ISSET (fd, &inp))
163     return n;
164     return 0;
165     }
166    
167    
168     static int
169     http_read_line (int fd, char * buf, size_t nbuf,
170     int nonblock, int * nn, int * eof)
171     {
172     char c;
173     int n, i;
174    
175     if (nn)
176     *nn = 0;
177     if (eof)
178     *eof = 0;
179     i = 0;
180     do {
181     if (nonblock == 1 && http_data_avail (fd) == 0) {
182     buf[i++] = '\0';
183     i = -1;
184     break;
185     }
186     n = recv (fd, &c, 1, 0);
187     if (n == -1)
188     break;
189     if (n == 0 || nbuf == 0 || c == '\n') {
190     if (n == 0) {
191     if (eof)
192     *eof = 1;
193     buf[i++] = '\0';
194     }
195     else {
196     buf[i++] = c;
197     buf[i] = '\0';
198     }
199     break;
200     }
201     else {
202     buf[i++] = c;
203     nbuf--;
204     }
205     } while (n > 0 && i != -1);
206    
207     if (nn)
208     *nn = i;
209     return 0;
210     }
211    
212    
213     static int
214     http_send_req (int fd, const char * host, const char * url)
215     {
216     char * p;
217     int n;
218    
219     if (*url == '/')
220     url++;
221     if (url == NULL)
222     url = "";
223     p = malloc (strlen (url) + strlen (host) + 64);
224     if (p == NULL)
225     BUG (0);
226     sprintf (p, "GET /%s HTTP/1.1\r\n"
227     "Host: %s\r\n"
228     "\r\n"
229     "\r\n",
230     url, host);
231     n = send (fd, p, strlen (p), 0);
232     free (p);
233     if (n == -1)
234     return SOCKET_ERROR;
235     return 0;
236     }
237    
238    
239     int
240     http_send_request2 (const char * url, http_hd_t * r_hd)
241     {
242     http_hd_t hd;
243     char * host = NULL, * p;
244     char tmpbuf[512];
245     int rc;
246    
247     memset (tmpbuf, 0, 512);
248     strncpy (tmpbuf, url, 512);
249    
250     if (strlen (url) < 10 || strncmp (url, "http://", 7))
251     return WPTERR_GENERAL;
252     url += 7;
253     p = strtok (tmpbuf+7, "/");
254     if (p == NULL)
255     return WPTERR_GENERAL;
256     host = strdup (p);
257     if (host == NULL)
258     BUG (0);
259     p = strchr (url, '/');
260     if (p == NULL) {
261     free (host);
262     return WPTERR_GENERAL;
263     }
264     rc = http_send_request (host, 80, p+1, &hd);
265     *r_hd = hd;
266     free (host);
267     return rc;
268     }
269    
270    
271     int
272     http_send_request (const char * host, int port, const char * url,
273     http_hd_t * r_hd)
274     {
275     http_hd_t hd;
276     int rc;
277    
278     http_hd_new (&hd);
279     rc = http_connect (host, port, &hd->fd);
280     if (!rc)
281     rc = http_send_req (hd->fd, host, url);
282     if (r_hd)
283     *r_hd = hd;
284     else
285     http_hd_free (hd);
286     return rc;
287     }
288    
289    
290     int
291     http_req_new (http_req_t * ctx)
292     {
293     http_req_t c;
294     c = calloc (1, sizeof * c);
295     if (c == NULL)
296     BUG (0);
297     *ctx = c;
298     return 0;
299     }
300    
301    
302     void
303     http_req_free (http_req_t ctx)
304     {
305     if (!ctx)
306     return;
307     http_head_free (ctx->head);
308     if (ctx->url)
309     free (ctx->url);
310     free (ctx);
311     }
312    
313    
314     static int
315     parse_statline (const char * buf, int * code)
316     {
317     int tmp = 0;
318    
319     if (strlen (buf) < 8 ||
320     (strncmp (buf, "HTTP/1.", 7)))
321     return WPTERR_GENERAL;
322     buf += 8; /* skip HTTP/1.x */
323     buf++; /* white space */
324     tmp = atoi (buf);
325     if (tmp == 0)
326     return WPTERR_GENERAL;
327     *code = tmp;
328     buf += 3;
329     buf++; /* whitespace */
330     return 0;
331     }
332    
333    
334     static int
335     parse_headers (int fd, http_head_t * r_head)
336     {
337     http_head_t h, head = NULL;
338     char buf[300];
339     int nn;
340     int rc;
341    
342     do {
343     rc = http_read_line (fd, buf, 299, 1, &nn, NULL);
344     if (rc)
345     return rc;
346     if (nn == 2)
347     break; /* reach empty line */
348     http_head_new (&h, buf);
349     if (head == NULL)
350     head = h;
351     else
352     http_head_add (head, h);
353     } while (rc == 0);
354     if (r_head)
355     *r_head = head;
356     else
357     http_head_free (head);
358     return 0;
359     }
360    
361    
362     static int
363     read_binary (int fd, int nlen, FILE * out)
364     {
365     char buf[1024+1];
366     int n;
367    
368     do
369     {
370     n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);
371     if (n == -1)
372     return SOCKET_ERROR;
373     if (n == 0)
374     break;
375     nlen -= n;
376     fwrite (buf, 1, n, out);
377     } while (nlen > 0);
378     return 0;
379     }
380    
381    
382     static int
383     parse_data (int fd, http_head_t head, FILE * out)
384     {
385     http_head_t h;
386     const char * s = "Content-Length: ", * val;
387     char buf[1024+1];
388     int nlen = 0, nn = 0, n, eof=0;
389     int rc;
390    
391     h = http_head_find (head, s, &val);
392     if (h)
393     nlen = atoi (val);
394     else {
395     h = http_head_find (head, "Connection: ", &val);
396     if (h == NULL || strncmp (val, "close", 4))
397     return WPTERR_GENERAL;
398     }
399    
400     h = http_head_find (head, "Content-Type: ", &val);
401     if (h == NULL)
402     return WPTERR_GENERAL;
403     if (strncmp (val, "text", 4))
404     return read_binary (fd, nlen, out);
405    
406     do {
407     rc = http_read_line (fd, buf, 1024, 1, &n, &eof);
408     if (rc)
409     return rc;
410     if (n > 0)
411     fwrite (buf, 1, n, out);
412     if (nlen > 0) {
413     nn += n;
414     if (nlen == nn)
415     break;
416     }
417     } while (eof == 0);
418     return 0;
419     }
420    
421    
422     static int
423     check_status (int code, int * statcode)
424     {
425     if (code != HTTP_STAT_200) {
426     if (statcode)
427     *statcode = code;
428     if (code == HTTP_STAT_400 ||
429     code == HTTP_STAT_403 ||
430     code == HTTP_STAT_404 ||
431     code == HTTP_STAT_405)
432     return WPTERR_GENERAL;
433     }
434     return 0;
435     }
436    
437    
438     int
439     http_parse_response (http_hd_t hd, int * statcode)
440     {
441     char buf[300];
442     int rc;
443     int code = 0, nn = 0;
444    
445     if (statcode)
446     *statcode = 0;
447     rc = http_read_line (hd->fd, buf, 299, 1, &nn, NULL);
448     if (rc)
449     return rc;
450     rc = parse_statline (buf, &code);
451     if (rc)
452     return rc;
453     rc = check_status (code, statcode);
454     if (rc)
455     return rc;
456     rc = parse_headers (hd->fd, &hd->head);
457     if (rc)
458     return rc;
459     return 0;
460     }
461    
462    
463     int
464     http_parse_data (http_hd_t hd, FILE * out)
465     {
466     int rc = 0;
467     rc = parse_data (hd->fd, hd->head, out);
468     http_close (hd->fd);
469     return rc;
470     }
471    
472    
473     int
474     http_hd_new (http_hd_t * r_hd)
475     {
476     http_hd_t hd;
477    
478     if (!r_hd)
479     return -1;
480     hd = calloc (1, sizeof * hd);
481     if (hd == NULL)
482     abort ();
483     *r_hd = hd;
484     return 0;
485     }
486    
487    
488     void
489     http_hd_free (http_hd_t hd)
490     {
491     if (!hd)
492     return;
493     http_head_free (hd->head);
494     http_close (hd->fd);
495     free (hd);
496     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26