| 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"); |
| 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); |
| 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 |