libpurple/protocols/gg/lib/http.c

changeset 35630
8e5d0d726b09
parent 35620
fb20cfee648a
parent 35627
fd11790cc4d6
child 37426
6fd4989b77e4
equal deleted inserted replaced
35629:5aecb81f23ab 35630:8e5d0d726b09
26 26
27 #include "strman.h" 27 #include "strman.h"
28 #include "network.h" 28 #include "network.h"
29 #include "libgadu.h" 29 #include "libgadu.h"
30 #include "resolver.h" 30 #include "resolver.h"
31 #include "internal.h"
31 32
32 #include <ctype.h> 33 #include <ctype.h>
33 #include <errno.h> 34 #include <errno.h>
34 #include <stdlib.h> 35 #include <stdlib.h>
35 #include <string.h> 36 #include <string.h>
60 * 61 *
61 * \return Zaalokowana struktura \c gg_http lub NULL, jeśli wystąpił błąd. 62 * \return Zaalokowana struktura \c gg_http lub NULL, jeśli wystąpił błąd.
62 * 63 *
63 * \ingroup http 64 * \ingroup http
64 */ 65 */
65 struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header) 66 struct gg_http *gg_http_connect(const char *hostname, int port, int async,
67 const char *method, const char *path, const char *header)
66 { 68 {
67 struct gg_http *h; 69 struct gg_http *h;
68 70
69 if (!hostname || !port || !method || !path || !header) { 71 if (!hostname || !port || !method || !path || !header) {
70 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n"); 72 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n");
133 } 135 }
134 136
135 h->fd = gg_connect(&addr_list[0], port, 0); 137 h->fd = gg_connect(&addr_list[0], port, 0);
136 138
137 if (h->fd == -1) { 139 if (h->fd == -1) {
138 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno)); 140 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() "
141 "connection failed (errno=%d, %s)\n",
142 errno, strerror(errno));
139 gg_http_free(h); 143 gg_http_free(h);
140 free(addr_list); 144 free(addr_list);
141 return NULL; 145 return NULL;
142 } 146 }
143 147
164 } 168 }
165 169
166 #ifndef DOXYGEN 170 #ifndef DOXYGEN
167 171
168 #define gg_http_error(x) \ 172 #define gg_http_error(x) \
169 close(h->fd); \ 173 if (h->fd > -1) \
174 close(h->fd); \
170 h->fd = -1; \ 175 h->fd = -1; \
171 h->state = GG_STATE_ERROR; \ 176 h->state = GG_STATE_ERROR; \
172 h->error = x; \ 177 h->error = x; \
173 return 0; 178 return 0;
174 179
238 if (h->state == GG_STATE_CONNECTING) { 243 if (h->state == GG_STATE_CONNECTING) {
239 int res = 0; 244 int res = 0;
240 socklen_t res_size = sizeof(res); 245 socklen_t res_size = sizeof(res);
241 246
242 if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { 247 if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
243 gg_debug(GG_DEBUG_MISC, "=> http, async connection failed (errno=%d, %s)\n", (res) ? res : errno , strerror((res) ? res : errno)); 248 gg_debug(GG_DEBUG_MISC, "=> http, async connection "
249 "failed (errno=%d, %s)\n", (res) ? res : errno,
250 strerror((res) ? res : errno));
244 close(h->fd); 251 close(h->fd);
245 h->fd = -1; 252 h->fd = -1;
246 h->state = GG_STATE_ERROR; 253 h->state = GG_STATE_ERROR;
247 h->error = GG_ERROR_CONNECTING; 254 h->error = GG_ERROR_CONNECTING;
248 if (res) 255 if (res)
259 int res; 266 int res;
260 267
261 res = send(h->fd, h->query, strlen(h->query), 0); 268 res = send(h->fd, h->query, strlen(h->query), 0);
262 269
263 if (res == -1 && errno != EINTR && errno != EAGAIN) { 270 if (res == -1 && errno != EINTR && errno != EAGAIN) {
264 gg_debug(GG_DEBUG_MISC, "=> http, send() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno); 271 gg_debug(GG_DEBUG_MISC, "=> http, send() failed "
272 "(len=%" GG_SIZE_FMT ", res=%d, errno=%d)\n",
273 strlen(h->query), res, errno);
265 gg_http_error(GG_ERROR_WRITING); 274 gg_http_error(GG_ERROR_WRITING);
266 } 275 }
267 276
268 if (res == -1) { 277 if (res == -1) {
269 gg_debug(GG_DEBUG_MISC, "=> http, non-critical send error (errno=%d, %s)\n", errno, strerror(errno)); 278 gg_debug(GG_DEBUG_MISC, "=> http, non-critical send "
279 "error (errno=%d, %s)\n",
280 errno, strerror(errno));
270 return 0; 281 return 0;
271 } 282 }
272 283
273 if ((size_t) res < strlen(h->query)) { 284 if ((size_t) res < strlen(h->query)) {
274 gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, sent=%d)\n", strlen(h->query), res); 285 gg_debug(GG_DEBUG_MISC, "=> http, partial header sent "
286 "(led=%" GG_SIZE_FMT ", sent=%d)\n",
287 strlen(h->query), res);
275 288
276 memmove(h->query, h->query + res, strlen(h->query) - res + 1); 289 memmove(h->query, h->query + res, strlen(h->query) - res + 1);
277 h->state = GG_STATE_SENDING_QUERY; 290 h->state = GG_STATE_SENDING_QUERY;
278 h->check = GG_CHECK_WRITE; 291 h->check = GG_CHECK_WRITE;
279 h->timeout = GG_DEFAULT_TIMEOUT; 292 h->timeout = GG_DEFAULT_TIMEOUT;
280 } else { 293 } else {
281 gg_debug(GG_DEBUG_MISC, "=> http, request sent (len=%d)\n", strlen(h->query)); 294 gg_debug(GG_DEBUG_MISC, "=> http, request sent (len=%"
295 GG_SIZE_FMT ")\n", strlen(h->query));
282 free(h->query); 296 free(h->query);
283 h->query = NULL; 297 h->query = NULL;
284 298
285 h->state = GG_STATE_READING_HEADER; 299 h->state = GG_STATE_READING_HEADER;
286 h->check = GG_CHECK_READ; 300 h->check = GG_CHECK_READ;
304 } 318 }
305 gg_http_error(GG_ERROR_READING); 319 gg_http_error(GG_ERROR_READING);
306 } 320 }
307 321
308 if (res == -1) { 322 if (res == -1) {
309 gg_debug(GG_DEBUG_MISC, "=> http, non-critical recv error (errno=%d, %s)\n", errno, strerror(errno)); 323 gg_debug(GG_DEBUG_MISC, "=> http, non-critical recv "
324 "error (errno=%d, %s)\n",
325 errno, strerror(errno));
310 return 0; 326 return 0;
311 } 327 }
312 328
313 if (res == 0) { 329 if (res == 0) {
314 gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n"); 330 gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n");
342 if ((tmp = strstr(h->header, "\r\n\r\n")) || (tmp = strstr(h->header, "\n\n"))) { 358 if ((tmp = strstr(h->header, "\r\n\r\n")) || (tmp = strstr(h->header, "\n\n"))) {
343 int sep_len = (*tmp == '\r') ? 4 : 2; 359 int sep_len = (*tmp == '\r') ? 4 : 2;
344 unsigned int left; 360 unsigned int left;
345 char *line; 361 char *line;
346 362
347 left = h->header_size - ((long)(tmp) - (long)(h->header) + sep_len); 363 left = h->header_size - ((size_t)(tmp) - (size_t)(h->header) + sep_len);
348 364
349 gg_debug(GG_DEBUG_MISC, "=> http, got all header (%d bytes, %d left)\n", h->header_size - left, left); 365 gg_debug(GG_DEBUG_MISC, "=> http, got all header "
366 "(%d bytes, %d left)\n",
367 h->header_size - left, left);
350 368
351 /* HTTP/1.1 200 OK */ 369 /* HTTP/1.1 200 OK */
352 if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) { 370 if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) {
353 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); 371 gg_debug(GG_DEBUG_MISC,
372 "=> -----BEGIN-HTTP-HEADER-----\n%s\n"
373 "=> -----END-HTTP-HEADER-----\n",
374 h->header);
354 375
355 gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n"); 376 gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n");
356 free(h->header); 377 free(h->header);
357 h->header = NULL; 378 h->header = NULL;
358 gg_http_error(GG_ERROR_CONNECTING); 379 gg_http_error(GG_ERROR_CONNECTING);
360 381
361 h->body_size = 0; 382 h->body_size = 0;
362 line = h->header; 383 line = h->header;
363 *tmp = 0; 384 *tmp = 0;
364 385
365 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); 386 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----"
387 "\n%s\n=> -----END-HTTP-HEADER-----\n",
388 h->header);
366 389
367 while (line) { 390 while (line) {
368 if (!strncasecmp(line, "Content-length: ", 16)) { 391 if (!strncasecmp(line, "Content-length: ", 16)) {
369 h->body_size = atoi(line + 16); 392 h->body_size = atoi(line + 16);
370 } 393 }
382 gg_debug(GG_DEBUG_MISC, "=> http, content-length too big\n"); 405 gg_debug(GG_DEBUG_MISC, "=> http, content-length too big\n");
383 h->body_size = GG_HTTP_MAX_LENGTH; 406 h->body_size = GG_HTTP_MAX_LENGTH;
384 } 407 }
385 408
386 if (left > h->body_size) { 409 if (left > h->body_size) {
387 gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left); 410 gg_debug(GG_DEBUG_MISC, "=> http, oversized "
411 "reply (%d bytes needed, "
412 "%d bytes left)\n", h->body_size, left);
388 h->body_size = left; 413 h->body_size = left;
389 } 414 }
390 415
391 gg_debug(GG_DEBUG_MISC, "=> http, body_size=%d\n", h->body_size); 416 gg_debug(GG_DEBUG_MISC, "=> http, body_size=%d\n", h->body_size);
392 417
393 if (!(h->body = malloc(h->body_size + 1))) { 418 if (!(h->body = malloc(h->body_size + 1))) {
394 gg_debug(GG_DEBUG_MISC, "=> http, not enough memory (%d bytes for body_buf)\n", h->body_size + 1); 419 gg_debug(GG_DEBUG_MISC, "=> http, not enough "
420 "memory (%d bytes for body_buf)\n",
421 h->body_size + 1);
395 free(h->header); 422 free(h->header);
396 h->header = NULL; 423 h->header = NULL;
397 gg_http_error(GG_ERROR_READING); 424 gg_http_error(GG_ERROR_READING);
398 } 425 }
399 426
415 if (h->state == GG_STATE_READING_DATA) { 442 if (h->state == GG_STATE_READING_DATA) {
416 char buf[1024]; 443 char buf[1024];
417 int res; 444 int res;
418 445
419 res = recv(h->fd, buf, sizeof(buf), 0); 446 res = recv(h->fd, buf, sizeof(buf), 0);
420 447
421 if (res == -1 && errno != EINTR && errno != EAGAIN) { 448 if (res == -1 && errno != EINTR && errno != EAGAIN) {
422 gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno); 449 gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno);
423 if (h->body) { 450 if (h->body) {
424 free(h->body); 451 free(h->body);
425 h->body = NULL; 452 h->body = NULL;
426 } 453 }
427 gg_http_error(GG_ERROR_READING); 454 gg_http_error(GG_ERROR_READING);
428 } 455 }
429 456
430 if (res == -1) { 457 if (res == -1) {
431 gg_debug(GG_DEBUG_MISC, "=> http, non-critical recv error (errno=%d, %s)\n", errno, strerror(errno)); 458 gg_debug(GG_DEBUG_MISC, "=> http, non-critical "
459 "recv error (errno=%d, %s)\n",
460 errno, strerror(errno));
432 return 0; 461 return 0;
433 } 462 }
434 463
435 if (res == 0) { 464 if (res == 0) {
436 if (h->body_done >= h->body_size) { 465 if (h->body_done >= h->body_size) {
437 gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n"); 466 gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n");
438 h->state = GG_STATE_PARSING; 467 h->state = GG_STATE_PARSING;
439 close(h->fd); 468 close(h->fd);
440 h->fd = -1; 469 h->fd = -1;
441 } else { 470 } else {
442 gg_debug(GG_DEBUG_MISC, "=> http, connection closed while reading (have %d, need %d)\n", h->body_done, h->body_size); 471 gg_debug(GG_DEBUG_MISC, "=> http, "
472 "connection closed while reading "
473 "(have %d, need %d)\n",
474 h->body_done, h->body_size);
443 if (h->body) { 475 if (h->body) {
444 free(h->body); 476 free(h->body);
445 h->body = NULL; 477 h->body = NULL;
446 } 478 }
447 gg_http_error(GG_ERROR_READING); 479 gg_http_error(GG_ERROR_READING);
453 gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of body\n", res); 485 gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of body\n", res);
454 486
455 if (h->body_done + res > h->body_size) { 487 if (h->body_done + res > h->body_size) {
456 char *tmp; 488 char *tmp;
457 489
458 gg_debug(GG_DEBUG_MISC, "=> http, too much data (%d bytes, %d needed), enlarging buffer\n", h->body_done + res, h->body_size); 490 gg_debug(GG_DEBUG_MISC, "=> http, too much data "
491 "(%d bytes, %d needed), enlarging buffer\n",
492 h->body_done + res, h->body_size);
459 493
460 if (!(tmp = realloc(h->body, h->body_done + res + 1))) { 494 if (!(tmp = realloc(h->body, h->body_done + res + 1))) {
461 gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for data (%d needed)\n", h->body_done + res + 1); 495 gg_debug(GG_DEBUG_MISC, "=> http, not enough "
496 "memory for data (%d needed)\n",
497 h->body_done + res + 1);
462 free(h->body); 498 free(h->body);
463 h->body = NULL; 499 h->body = NULL;
464 gg_http_error(GG_ERROR_READING); 500 gg_http_error(GG_ERROR_READING);
465 } 501 }
466 502

mercurial