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

Contents of /trunk/Src/wptHTTP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show 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 /* 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