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

Annotation of /trunk/Src/wptHTTP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations)
Wed Oct 12 10:04:26 2005 UTC (19 years, 4 months ago) by twoaday
File MIME type: text/plain
File size: 9830 byte(s)
First testing phase finished.
Provide bug fixes for a lot of (minor) problems.

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26