static int http_read_stream(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int err, new_location, read_ret, seek_ret; if (!s->hd) return AVERROR_EOF; if (s->end_chunked_post && !s->end_header) { err = http_read_header(h, &new_location); if (err < 0) return err; } if (s->chunksize >= 0) { if (!s->chunksize) { char line[32]; do { if ((err = http_get_line(s, line, sizeof(line))) < 0) return err; } while (!*line); /* skip CR LF from last chunk */ s->chunksize = strtoll(line, NULL, 16); av_log(NULL, AV_LOG_TRACE, "Chunked encoding data size: %"PRId64"'\n", s->chunksize); if (!s->chunksize) return 0; } size = FFMIN(size, s->chunksize); } #if CONFIG_ZLIB if (s->compressed) return http_buf_read_compressed(h, buf, size); #endif /* CONFIG_ZLIB */ read_ret = http_buf_read(h, buf, size); if (read_ret < 0 && s->reconnect && !h->is_streamed && s->filesize > 0 && s->off < s->filesize) { av_log(h, AV_LOG_INFO, "Will reconnect at %"PRId64".\n", s->off); seek_ret = http_seek_internal(h, s->off, SEEK_SET, 1); if (seek_ret != s->off) { av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRId64".\n", s->off); return read_ret; } read_ret = http_buf_read(h, buf, size); } return read_ret; }
static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int ret; if (!s->inflate_buffer) { s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE); if (!s->inflate_buffer) return AVERROR(ENOMEM); } if (s->inflate_stream.avail_in == 0) { int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE); if (read <= 0) return read; s->inflate_stream.next_in = s->inflate_buffer; s->inflate_stream.avail_in = read; } s->inflate_stream.avail_out = size; s->inflate_stream.next_out = buf; ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH); if (ret != Z_OK && ret != Z_STREAM_END) av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n", ret, s->inflate_stream.msg); return size - s->inflate_stream.avail_out; }
static int http_read_stream(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int err, new_location; if (!s->hd) return AVERROR_EOF; if (s->end_chunked_post && !s->end_header) { err = http_read_header(h, &new_location); if (err < 0) return err; } if (s->chunksize >= 0) { if (!s->chunksize) { char line[32]; for (;;) { do { if ((err = http_get_line(s, line, sizeof(line))) < 0) return err; } while (!*line); /* skip CR LF from last chunk */ s->chunksize = strtoll(line, NULL, 16); av_log(NULL, AV_LOG_TRACE, "Chunked encoding data size: %"PRId64"'\n", s->chunksize); if (!s->chunksize) return 0; break; } } size = FFMIN(size, s->chunksize); } #if CONFIG_ZLIB if (s->compressed) return http_buf_read_compressed(h, buf, size); #endif /* CONFIG_ZLIB */ return http_buf_read(h, buf, size); }
struct http_request *http_parse_request(struct http_channel *c, struct http_buf **queue, int len) { struct http_request *r = nmem_malloc(c->nmem, sizeof(*r)); char *p, *p2; char *start = nmem_malloc(c->nmem, len+1); char *buf = start; if (http_buf_read(c->http_server, queue, buf, len) < len) { yaz_log(YLOG_WARN, "http_buf_read < len (%d)", len); return 0; } r->search = ""; r->channel = c; r->arguments = 0; r->headers = 0; r->content_buf = 0; r->content_len = 0; // Parse first line for (p = buf, p2 = r->method; *p && *p != ' ' && p - buf < 19; p++) *(p2++) = *p; if (*p != ' ') { yaz_log(YLOG_WARN, "Unexpected HTTP method in request"); return 0; } *p2 = '\0'; if (!(buf = strchr(buf, ' '))) { yaz_log(YLOG_WARN, "Missing Request-URI in HTTP request"); return 0; } buf++; if (!(p = strchr(buf, ' '))) { yaz_log(YLOG_WARN, "HTTP Request-URI not terminated (too long?)"); return 0; } *(p++) = '\0'; if ((p2 = strchr(buf, '?'))) // Do we have arguments? *(p2++) = '\0'; r->path = nmem_strdup(c->nmem, buf); if (p2) { r->search = nmem_strdup(c->nmem, p2); // Parse Arguments http_parse_arguments(r, c->nmem, p2); } buf = p; if (strncmp(buf, "HTTP/", 5)) strcpy(r->http_version, "1.0"); else { size_t skipped; buf += 5; // strlen("HTTP/") p = (char*) next_crlf(buf, &skipped); if (!p || skipped < 3 || skipped > 5) return 0; memcpy(r->http_version, buf, skipped); r->http_version[skipped] = '\0'; buf = p; } strcpy(c->version, r->http_version); r->headers = 0; while (*buf) { size_t skipped; p = (char *) next_crlf(buf, &skipped); if (!p) { return 0; } else if (skipped == 0) { buf = p; break; } else { char *cp; char *n_v = nmem_malloc(c->nmem, skipped+1); struct http_header *h = nmem_malloc(c->nmem, sizeof(*h)); memcpy(n_v, buf, skipped); n_v[skipped] = '\0'; if (!(cp = strchr(n_v, ':'))) return 0; h->name = nmem_strdupn(c->nmem, n_v, cp - n_v); cp++; while (isspace(*cp)) cp++; h->value = nmem_strdup(c->nmem, cp); h->next = r->headers; r->headers = h; buf = p; } } // determine if we do keep alive if (!strcmp(c->version, "1.0")) { const char *v = http_lookup_header(r->headers, "Connection"); if (v && !strcmp(v, "Keep-Alive")) c->keep_alive = 1; else c->keep_alive = 0; } else { const char *v = http_lookup_header(r->headers, "Connection"); if (v && !strcmp(v, "close")) c->keep_alive = 0; else c->keep_alive = 1; } if (buf < start + len) { const char *content_type = http_lookup_header(r->headers, "Content-Type"); r->content_len = start + len - buf; r->content_buf = buf; if (!yaz_strcmp_del("application/x-www-form-urlencoded", content_type, "; ")) { http_parse_arguments(r, c->nmem, r->content_buf); } } return r; }