Commit | Line | Data |
---|---|---|
558b86a5 | 1 | /* |
20566eb0 | 2 | * HTTP protocol for avconv client |
406792e7 | 3 | * Copyright (c) 2000, 2001 Fabrice Bellard |
558b86a5 | 4 | * |
2912e87a | 5 | * This file is part of Libav. |
558b86a5 | 6 | * |
2912e87a | 7 | * Libav is free software; you can redistribute it and/or |
558b86a5 LB |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
2912e87a | 12 | * Libav is distributed in the hope that it will be useful, |
558b86a5 LB |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
2912e87a | 18 | * License along with Libav; if not, write to the Free Software |
558b86a5 LB |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ | |
245976da | 21 | |
245976da | 22 | #include "libavutil/avstring.h" |
558b86a5 LB |
23 | #include "avformat.h" |
24 | #include <unistd.h> | |
e4a9e3cc | 25 | #include "internal.h" |
558b86a5 | 26 | #include "network.h" |
6964d510 | 27 | #include "http.h" |
a5e979f4 | 28 | #include "os_support.h" |
9405f733 | 29 | #include "httpauth.h" |
0589da0a | 30 | #include "url.h" |
6ed04040 | 31 | #include "libavutil/opt.h" |
558b86a5 | 32 | |
20566eb0 | 33 | /* XXX: POST protocol is not completely implemented because avconv uses |
e42dba48 | 34 | only a subset of it. */ |
558b86a5 | 35 | |
558b86a5 LB |
36 | /* used for protocol handling */ |
37 | #define BUFFER_SIZE 1024 | |
558b86a5 LB |
38 | #define MAX_REDIRECTS 8 |
39 | ||
40 | typedef struct { | |
4167ba0b | 41 | const AVClass *class; |
558b86a5 LB |
42 | URLContext *hd; |
43 | unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end; | |
44 | int line_count; | |
45 | int http_code; | |
7995ed8e | 46 | int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */ |
bc5c918e | 47 | int64_t off, filesize; |
e55ebcc3 | 48 | char location[MAX_URL_SIZE]; |
9405f733 | 49 | HTTPAuthState auth_state; |
6964d510 | 50 | unsigned char headers[BUFFER_SIZE]; |
f240ed18 | 51 | int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */ |
558b86a5 LB |
52 | } HTTPContext; |
53 | ||
4167ba0b MS |
54 | #define OFFSET(x) offsetof(HTTPContext, x) |
55 | static const AVOption options[] = { | |
145f741e | 56 | {"chunksize", "use chunked transfer-encoding for posts, -1 disables it, 0 enables it", OFFSET(chunksize), AV_OPT_TYPE_INT64, {.dbl = 0}, -1, 0 }, /* Default to 0, for chunked POSTs */ |
4167ba0b MS |
57 | {NULL} |
58 | }; | |
59 | static const AVClass httpcontext_class = { | |
f0029cbc AK |
60 | .class_name = "HTTP", |
61 | .item_name = av_default_item_name, | |
62 | .option = options, | |
63 | .version = LIBAVUTIL_VERSION_INT, | |
4167ba0b MS |
64 | }; |
65 | ||
558b86a5 LB |
66 | static int http_connect(URLContext *h, const char *path, const char *hoststr, |
67 | const char *auth, int *new_location); | |
558b86a5 | 68 | |
6964d510 JA |
69 | void ff_http_set_headers(URLContext *h, const char *headers) |
70 | { | |
71 | HTTPContext *s = h->priv_data; | |
72 | int len = strlen(headers); | |
73 | ||
74 | if (len && strcmp("\r\n", headers + len - 2)) | |
c60112f2 | 75 | av_log(h, AV_LOG_ERROR, "No trailing CRLF found in HTTP header.\n"); |
6964d510 JA |
76 | |
77 | av_strlcpy(s->headers, headers, sizeof(s->headers)); | |
78 | } | |
558b86a5 | 79 | |
db302347 MS |
80 | void ff_http_init_auth_state(URLContext *dest, const URLContext *src) |
81 | { | |
82 | memcpy(&((HTTPContext*)dest->priv_data)->auth_state, | |
83 | &((HTTPContext*)src->priv_data)->auth_state, sizeof(HTTPAuthState)); | |
84 | } | |
85 | ||
558b86a5 LB |
86 | /* return non zero if error */ |
87 | static int http_open_cnx(URLContext *h) | |
88 | { | |
183baead MS |
89 | const char *path, *proxy_path, *lower_proto = "tcp"; |
90 | char hostname[1024], hoststr[1024], proto[10]; | |
558b86a5 LB |
91 | char auth[1024]; |
92 | char path1[1024]; | |
93 | char buf[1024]; | |
94 | int port, use_proxy, err, location_changed = 0, redirects = 0; | |
9405f733 | 95 | HTTPAuthType cur_auth_type; |
558b86a5 LB |
96 | HTTPContext *s = h->priv_data; |
97 | URLContext *hd = NULL; | |
98 | ||
99 | proxy_path = getenv("http_proxy"); | |
100 | use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && | |
f7d78f36 | 101 | av_strstart(proxy_path, "http://", NULL); |
558b86a5 LB |
102 | |
103 | /* fill the dest addr */ | |
104 | redo: | |
105 | /* needed in any case to build the host string */ | |
183baead MS |
106 | av_url_split(proto, sizeof(proto), auth, sizeof(auth), |
107 | hostname, sizeof(hostname), &port, | |
f984dcf6 | 108 | path1, sizeof(path1), s->location); |
57b5555c | 109 | ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL); |
558b86a5 LB |
110 | |
111 | if (use_proxy) { | |
f3bfe388 | 112 | av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, |
f984dcf6 | 113 | NULL, 0, proxy_path); |
558b86a5 LB |
114 | path = s->location; |
115 | } else { | |
116 | if (path1[0] == '\0') | |
117 | path = "/"; | |
118 | else | |
119 | path = path1; | |
120 | } | |
183baead MS |
121 | if (!strcmp(proto, "https")) { |
122 | lower_proto = "tls"; | |
123 | if (port < 0) | |
124 | port = 443; | |
125 | } | |
558b86a5 LB |
126 | if (port < 0) |
127 | port = 80; | |
128 | ||
183baead | 129 | ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL); |
59d96941 | 130 | err = ffurl_open(&hd, buf, AVIO_FLAG_READ_WRITE); |
558b86a5 LB |
131 | if (err < 0) |
132 | goto fail; | |
133 | ||
134 | s->hd = hd; | |
9405f733 | 135 | cur_auth_type = s->auth_state.auth_type; |
558b86a5 LB |
136 | if (http_connect(h, path, hoststr, auth, &location_changed) < 0) |
137 | goto fail; | |
9405f733 MS |
138 | if (s->http_code == 401) { |
139 | if (cur_auth_type == HTTP_AUTH_NONE && s->auth_state.auth_type != HTTP_AUTH_NONE) { | |
e52a9145 | 140 | ffurl_close(hd); |
9405f733 MS |
141 | goto redo; |
142 | } else | |
143 | goto fail; | |
144 | } | |
7e35d859 ME |
145 | if ((s->http_code == 301 || s->http_code == 302 || s->http_code == 303 || s->http_code == 307) |
146 | && location_changed == 1) { | |
558b86a5 | 147 | /* url moved, get next */ |
e52a9145 | 148 | ffurl_close(hd); |
558b86a5 | 149 | if (redirects++ >= MAX_REDIRECTS) |
6f3e0b21 | 150 | return AVERROR(EIO); |
558b86a5 LB |
151 | location_changed = 0; |
152 | goto redo; | |
153 | } | |
154 | return 0; | |
155 | fail: | |
156 | if (hd) | |
e52a9145 | 157 | ffurl_close(hd); |
701ea516 | 158 | s->hd = NULL; |
6f3e0b21 | 159 | return AVERROR(EIO); |
558b86a5 LB |
160 | } |
161 | ||
162 | static int http_open(URLContext *h, const char *uri, int flags) | |
163 | { | |
a9a3364c | 164 | HTTPContext *s = h->priv_data; |
558b86a5 LB |
165 | |
166 | h->is_streamed = 1; | |
167 | ||
558b86a5 | 168 | s->filesize = -1; |
e55ebcc3 | 169 | av_strlcpy(s->location, uri, sizeof(s->location)); |
558b86a5 | 170 | |
9290f15d | 171 | return http_open_cnx(h); |
558b86a5 LB |
172 | } |
173 | static int http_getc(HTTPContext *s) | |
174 | { | |
175 | int len; | |
176 | if (s->buf_ptr >= s->buf_end) { | |
bc371aca | 177 | len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE); |
558b86a5 | 178 | if (len < 0) { |
6f3e0b21 | 179 | return AVERROR(EIO); |
558b86a5 LB |
180 | } else if (len == 0) { |
181 | return -1; | |
182 | } else { | |
183 | s->buf_ptr = s->buffer; | |
184 | s->buf_end = s->buffer + len; | |
185 | } | |
186 | } | |
187 | return *s->buf_ptr++; | |
188 | } | |
189 | ||
682d49f4 PH |
190 | static int http_get_line(HTTPContext *s, char *line, int line_size) |
191 | { | |
192 | int ch; | |
193 | char *q; | |
194 | ||
195 | q = line; | |
196 | for(;;) { | |
197 | ch = http_getc(s); | |
198 | if (ch < 0) | |
199 | return AVERROR(EIO); | |
200 | if (ch == '\n') { | |
201 | /* process line */ | |
202 | if (q > line && q[-1] == '\r') | |
203 | q--; | |
204 | *q = '\0'; | |
205 | ||
206 | return 0; | |
207 | } else { | |
208 | if ((q - line) < line_size - 1) | |
209 | *q++ = ch; | |
210 | } | |
211 | } | |
212 | } | |
213 | ||
558b86a5 LB |
214 | static int process_line(URLContext *h, char *line, int line_count, |
215 | int *new_location) | |
216 | { | |
217 | HTTPContext *s = h->priv_data; | |
db979afe | 218 | char *tag, *p, *end; |
558b86a5 LB |
219 | |
220 | /* end of header */ | |
221 | if (line[0] == '\0') | |
222 | return 0; | |
223 | ||
224 | p = line; | |
225 | if (line_count == 0) { | |
226 | while (!isspace(*p) && *p != '\0') | |
227 | p++; | |
228 | while (isspace(*p)) | |
229 | p++; | |
db979afe | 230 | s->http_code = strtol(p, &end, 10); |
a52dc730 | 231 | |
dfd2a005 | 232 | av_dlog(NULL, "http_code=%d\n", s->http_code); |
a52dc730 | 233 | |
9405f733 MS |
234 | /* error codes are 4xx and 5xx, but regard 401 as a success, so we |
235 | * don't abort until all headers have been parsed. */ | |
db979afe MS |
236 | if (s->http_code >= 400 && s->http_code < 600 && s->http_code != 401) { |
237 | end += strspn(end, SPACE_CHARS); | |
c60112f2 | 238 | av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", |
db979afe | 239 | s->http_code, end); |
7b19aa64 | 240 | return -1; |
db979afe | 241 | } |
558b86a5 LB |
242 | } else { |
243 | while (*p != '\0' && *p != ':') | |
244 | p++; | |
245 | if (*p != ':') | |
246 | return 1; | |
247 | ||
248 | *p = '\0'; | |
249 | tag = line; | |
250 | p++; | |
251 | while (isspace(*p)) | |
252 | p++; | |
bb3244de | 253 | if (!av_strcasecmp(tag, "Location")) { |
558b86a5 LB |
254 | strcpy(s->location, p); |
255 | *new_location = 1; | |
bb3244de | 256 | } else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) { |
558b86a5 | 257 | s->filesize = atoll(p); |
bb3244de | 258 | } else if (!av_strcasecmp (tag, "Content-Range")) { |
558b86a5 LB |
259 | /* "bytes $from-$to/$document_size" */ |
260 | const char *slash; | |
261 | if (!strncmp (p, "bytes ", 6)) { | |
262 | p += 6; | |
263 | s->off = atoll(p); | |
264 | if ((slash = strchr(p, '/')) && strlen(slash) > 0) | |
265 | s->filesize = atoll(slash+1); | |
266 | } | |
267 | h->is_streamed = 0; /* we _can_ in fact seek */ | |
bb3244de | 268 | } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5)) { |
346ea9e2 | 269 | h->is_streamed = 0; |
bb3244de | 270 | } else if (!av_strcasecmp (tag, "Transfer-Encoding") && !av_strncasecmp(p, "chunked", 7)) { |
7995ed8e PH |
271 | s->filesize = -1; |
272 | s->chunksize = 0; | |
bb3244de | 273 | } else if (!av_strcasecmp (tag, "WWW-Authenticate")) { |
9405f733 | 274 | ff_http_auth_handle_header(&s->auth_state, tag, p); |
bb3244de | 275 | } else if (!av_strcasecmp (tag, "Authentication-Info")) { |
9405f733 | 276 | ff_http_auth_handle_header(&s->auth_state, tag, p); |
bb3244de | 277 | } else if (!av_strcasecmp (tag, "Connection")) { |
f240ed18 MS |
278 | if (!strcmp(p, "close")) |
279 | s->willclose = 1; | |
558b86a5 LB |
280 | } |
281 | } | |
282 | return 1; | |
283 | } | |
284 | ||
6964d510 JA |
285 | static inline int has_header(const char *str, const char *header) |
286 | { | |
287 | /* header + 2 to skip over CRLF prefix. (make sure you have one!) */ | |
288 | return av_stristart(str, header + 2, NULL) || av_stristr(str, header); | |
289 | } | |
290 | ||
558b86a5 LB |
291 | static int http_connect(URLContext *h, const char *path, const char *hoststr, |
292 | const char *auth, int *new_location) | |
293 | { | |
294 | HTTPContext *s = h->priv_data; | |
682d49f4 PH |
295 | int post, err; |
296 | char line[1024]; | |
4ceb8b34 | 297 | char headers[1024] = ""; |
9405f733 | 298 | char *authstr = NULL; |
bc5c918e | 299 | int64_t off = s->off; |
6964d510 | 300 | int len = 0; |
558b86a5 LB |
301 | |
302 | ||
303 | /* send http header */ | |
59d96941 | 304 | post = h->flags & AVIO_FLAG_WRITE; |
9405f733 MS |
305 | authstr = ff_http_auth_create_response(&s->auth_state, auth, path, |
306 | post ? "POST" : "GET"); | |
6964d510 JA |
307 | |
308 | /* set default headers if needed */ | |
309 | if (!has_header(s->headers, "\r\nUser-Agent: ")) | |
310 | len += av_strlcatf(headers + len, sizeof(headers) - len, | |
311 | "User-Agent: %s\r\n", LIBAVFORMAT_IDENT); | |
312 | if (!has_header(s->headers, "\r\nAccept: ")) | |
313 | len += av_strlcpy(headers + len, "Accept: */*\r\n", | |
314 | sizeof(headers) - len); | |
315 | if (!has_header(s->headers, "\r\nRange: ")) | |
316 | len += av_strlcatf(headers + len, sizeof(headers) - len, | |
4ceb8b34 | 317 | "Range: bytes=%"PRId64"-\r\n", s->off); |
6964d510 JA |
318 | if (!has_header(s->headers, "\r\nConnection: ")) |
319 | len += av_strlcpy(headers + len, "Connection: close\r\n", | |
320 | sizeof(headers)-len); | |
321 | if (!has_header(s->headers, "\r\nHost: ")) | |
322 | len += av_strlcatf(headers + len, sizeof(headers) - len, | |
323 | "Host: %s\r\n", hoststr); | |
324 | ||
325 | /* now add in custom headers */ | |
326 | av_strlcpy(headers+len, s->headers, sizeof(headers)-len); | |
327 | ||
558b86a5 LB |
328 | snprintf(s->buffer, sizeof(s->buffer), |
329 | "%s %s HTTP/1.1\r\n" | |
9405f733 | 330 | "%s" |
6964d510 | 331 | "%s" |
08f7a8ac | 332 | "%s" |
558b86a5 LB |
333 | "\r\n", |
334 | post ? "POST" : "GET", | |
335 | path, | |
077026cc | 336 | post && s->chunksize >= 0 ? "Transfer-Encoding: chunked\r\n" : "", |
6964d510 JA |
337 | headers, |
338 | authstr ? authstr : ""); | |
558b86a5 | 339 | |
9405f733 | 340 | av_freep(&authstr); |
925e908b | 341 | if (ffurl_write(s->hd, s->buffer, strlen(s->buffer)) < 0) |
6f3e0b21 | 342 | return AVERROR(EIO); |
558b86a5 LB |
343 | |
344 | /* init input buffer */ | |
345 | s->buf_ptr = s->buffer; | |
346 | s->buf_end = s->buffer; | |
347 | s->line_count = 0; | |
348 | s->off = 0; | |
ecb4a895 | 349 | s->filesize = -1; |
f240ed18 | 350 | s->willclose = 0; |
558b86a5 | 351 | if (post) { |
dd798dcd MS |
352 | /* Pretend that it did work. We didn't read any header yet, since |
353 | * we've still to send the POST data, but the code calling this | |
354 | * function will check http_code after we return. */ | |
355 | s->http_code = 200; | |
558b86a5 LB |
356 | return 0; |
357 | } | |
077026cc | 358 | s->chunksize = -1; |
558b86a5 LB |
359 | |
360 | /* wait for header */ | |
558b86a5 | 361 | for(;;) { |
682d49f4 | 362 | if (http_get_line(s, line, sizeof(line)) < 0) |
6f3e0b21 | 363 | return AVERROR(EIO); |
a52dc730 | 364 | |
dfd2a005 | 365 | av_dlog(NULL, "header='%s'\n", line); |
a52dc730 | 366 | |
2b01a520 JM |
367 | err = process_line(h, line, s->line_count, new_location); |
368 | if (err < 0) | |
369 | return err; | |
370 | if (err == 0) | |
371 | break; | |
372 | s->line_count++; | |
558b86a5 LB |
373 | } |
374 | ||
375 | return (off == s->off) ? 0 : -1; | |
376 | } | |
377 | ||
378 | ||
379 | static int http_read(URLContext *h, uint8_t *buf, int size) | |
380 | { | |
381 | HTTPContext *s = h->priv_data; | |
382 | int len; | |
383 | ||
7995ed8e PH |
384 | if (s->chunksize >= 0) { |
385 | if (!s->chunksize) { | |
386 | char line[32]; | |
387 | ||
388 | for(;;) { | |
389 | do { | |
390 | if (http_get_line(s, line, sizeof(line)) < 0) | |
391 | return AVERROR(EIO); | |
392 | } while (!*line); /* skip CR LF from last chunk */ | |
393 | ||
394 | s->chunksize = strtoll(line, NULL, 16); | |
395 | ||
dfd2a005 | 396 | av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n", s->chunksize); |
7995ed8e PH |
397 | |
398 | if (!s->chunksize) | |
399 | return 0; | |
400 | break; | |
401 | } | |
402 | } | |
403 | size = FFMIN(size, s->chunksize); | |
404 | } | |
558b86a5 LB |
405 | /* read bytes from input buffer first */ |
406 | len = s->buf_end - s->buf_ptr; | |
407 | if (len > 0) { | |
408 | if (len > size) | |
409 | len = size; | |
410 | memcpy(buf, s->buf_ptr, len); | |
411 | s->buf_ptr += len; | |
412 | } else { | |
f240ed18 MS |
413 | if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize) |
414 | return AVERROR_EOF; | |
bc371aca | 415 | len = ffurl_read(s->hd, buf, size); |
558b86a5 | 416 | } |
7995ed8e | 417 | if (len > 0) { |
558b86a5 | 418 | s->off += len; |
7995ed8e PH |
419 | if (s->chunksize > 0) |
420 | s->chunksize -= len; | |
421 | } | |
558b86a5 LB |
422 | return len; |
423 | } | |
424 | ||
425 | /* used only when posting data */ | |
27241cbf | 426 | static int http_write(URLContext *h, const uint8_t *buf, int size) |
558b86a5 | 427 | { |
f2b9b19f | 428 | char temp[11] = ""; /* 32-bit hex + CRLF + nul */ |
08f7a8ac TH |
429 | int ret; |
430 | char crlf[] = "\r\n"; | |
558b86a5 | 431 | HTTPContext *s = h->priv_data; |
08f7a8ac TH |
432 | |
433 | if (s->chunksize == -1) { | |
a6a91589 | 434 | /* non-chunked data is sent without any special encoding */ |
925e908b | 435 | return ffurl_write(s->hd, buf, size); |
08f7a8ac TH |
436 | } |
437 | ||
438 | /* silently ignore zero-size data since chunk encoding that would | |
439 | * signal EOF */ | |
440 | if (size > 0) { | |
441 | /* upload data using chunked encoding */ | |
17b1493f | 442 | snprintf(temp, sizeof(temp), "%x\r\n", size); |
f2b9b19f | 443 | |
925e908b AK |
444 | if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 || |
445 | (ret = ffurl_write(s->hd, buf, size)) < 0 || | |
446 | (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0) | |
08f7a8ac TH |
447 | return ret; |
448 | } | |
449 | return size; | |
558b86a5 LB |
450 | } |
451 | ||
452 | static int http_close(URLContext *h) | |
453 | { | |
08f7a8ac TH |
454 | int ret = 0; |
455 | char footer[] = "0\r\n\r\n"; | |
558b86a5 | 456 | HTTPContext *s = h->priv_data; |
08f7a8ac TH |
457 | |
458 | /* signal end of chunked encoding if used */ | |
59d96941 | 459 | if ((h->flags & AVIO_FLAG_WRITE) && s->chunksize != -1) { |
925e908b | 460 | ret = ffurl_write(s->hd, footer, sizeof(footer) - 1); |
08f7a8ac TH |
461 | ret = ret > 0 ? 0 : ret; |
462 | } | |
463 | ||
701ea516 | 464 | if (s->hd) |
e52a9145 | 465 | ffurl_close(s->hd); |
08f7a8ac | 466 | return ret; |
558b86a5 LB |
467 | } |
468 | ||
bc5c918e | 469 | static int64_t http_seek(URLContext *h, int64_t off, int whence) |
558b86a5 LB |
470 | { |
471 | HTTPContext *s = h->priv_data; | |
472 | URLContext *old_hd = s->hd; | |
bc5c918e | 473 | int64_t old_off = s->off; |
08c8e66a BC |
474 | uint8_t old_buf[BUFFER_SIZE]; |
475 | int old_buf_size; | |
558b86a5 LB |
476 | |
477 | if (whence == AVSEEK_SIZE) | |
478 | return s->filesize; | |
479 | else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed) | |
480 | return -1; | |
481 | ||
482 | /* we save the old context in case the seek fails */ | |
08c8e66a BC |
483 | old_buf_size = s->buf_end - s->buf_ptr; |
484 | memcpy(old_buf, s->buf_ptr, old_buf_size); | |
558b86a5 LB |
485 | s->hd = NULL; |
486 | if (whence == SEEK_CUR) | |
487 | off += s->off; | |
488 | else if (whence == SEEK_END) | |
489 | off += s->filesize; | |
490 | s->off = off; | |
491 | ||
492 | /* if it fails, continue on old connection */ | |
493 | if (http_open_cnx(h) < 0) { | |
08c8e66a BC |
494 | memcpy(s->buffer, old_buf, old_buf_size); |
495 | s->buf_ptr = s->buffer; | |
496 | s->buf_end = s->buffer + old_buf_size; | |
558b86a5 LB |
497 | s->hd = old_hd; |
498 | s->off = old_off; | |
499 | return -1; | |
500 | } | |
e52a9145 | 501 | ffurl_close(old_hd); |
558b86a5 LB |
502 | return off; |
503 | } | |
504 | ||
f0a80394 RB |
505 | static int |
506 | http_get_file_handle(URLContext *h) | |
507 | { | |
508 | HTTPContext *s = h->priv_data; | |
1869ea03 | 509 | return ffurl_get_file_handle(s->hd); |
f0a80394 RB |
510 | } |
511 | ||
183baead | 512 | #if CONFIG_HTTP_PROTOCOL |
c6610a21 | 513 | URLProtocol ff_http_protocol = { |
f35ff97f AK |
514 | .name = "http", |
515 | .url_open = http_open, | |
516 | .url_read = http_read, | |
517 | .url_write = http_write, | |
518 | .url_seek = http_seek, | |
519 | .url_close = http_close, | |
f0a80394 | 520 | .url_get_file_handle = http_get_file_handle, |
f35ff97f AK |
521 | .priv_data_size = sizeof(HTTPContext), |
522 | .priv_data_class = &httpcontext_class, | |
558b86a5 | 523 | }; |
183baead MS |
524 | #endif |
525 | #if CONFIG_HTTPS_PROTOCOL | |
526 | URLProtocol ff_https_protocol = { | |
527 | .name = "https", | |
528 | .url_open = http_open, | |
529 | .url_read = http_read, | |
530 | .url_write = http_write, | |
531 | .url_seek = http_seek, | |
532 | .url_close = http_close, | |
533 | .url_get_file_handle = http_get_file_handle, | |
534 | .priv_data_size = sizeof(HTTPContext), | |
535 | .priv_data_class = &httpcontext_class, | |
536 | }; | |
537 | #endif |