comparison http.c @ 5879:61062082488b libavformat

Split out http authentication handling into a separate file This prepares for adding support for more authentication methods
author mstorsjo
date Wed, 24 Mar 2010 22:32:05 +0000
parents d605f589f0be
children 7fdda2416684
comparison
equal deleted inserted replaced
5878:01b33a7f96ee 5879:61062082488b
17 * You should have received a copy of the GNU Lesser General Public 17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software 18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22 #include "libavutil/base64.h"
23 #include "libavutil/avstring.h" 22 #include "libavutil/avstring.h"
24 #include "avformat.h" 23 #include "avformat.h"
25 #include <unistd.h> 24 #include <unistd.h>
26 #include <strings.h> 25 #include <strings.h>
27 #include "internal.h" 26 #include "internal.h"
28 #include "network.h" 27 #include "network.h"
29 #include "os_support.h" 28 #include "os_support.h"
29 #include "httpauth.h"
30 30
31 /* XXX: POST protocol is not completely implemented because ffmpeg uses 31 /* XXX: POST protocol is not completely implemented because ffmpeg uses
32 only a subset of it. */ 32 only a subset of it. */
33 33
34 /* used for protocol handling */ 34 /* used for protocol handling */
42 int line_count; 42 int line_count;
43 int http_code; 43 int http_code;
44 int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */ 44 int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */
45 int64_t off, filesize; 45 int64_t off, filesize;
46 char location[URL_SIZE]; 46 char location[URL_SIZE];
47 HTTPAuthState auth_state;
47 } HTTPContext; 48 } HTTPContext;
48 49
49 static int http_connect(URLContext *h, const char *path, const char *hoststr, 50 static int http_connect(URLContext *h, const char *path, const char *hoststr,
50 const char *auth, int *new_location); 51 const char *auth, int *new_location);
51 static int http_write(URLContext *h, uint8_t *buf, int size); 52 static int http_write(URLContext *h, uint8_t *buf, int size);
58 char hostname[1024], hoststr[1024]; 59 char hostname[1024], hoststr[1024];
59 char auth[1024]; 60 char auth[1024];
60 char path1[1024]; 61 char path1[1024];
61 char buf[1024]; 62 char buf[1024];
62 int port, use_proxy, err, location_changed = 0, redirects = 0; 63 int port, use_proxy, err, location_changed = 0, redirects = 0;
64 HTTPAuthType cur_auth_type;
63 HTTPContext *s = h->priv_data; 65 HTTPContext *s = h->priv_data;
64 URLContext *hd = NULL; 66 URLContext *hd = NULL;
65 67
66 proxy_path = getenv("http_proxy"); 68 proxy_path = getenv("http_proxy");
67 use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && 69 use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
91 err = url_open(&hd, buf, URL_RDWR); 93 err = url_open(&hd, buf, URL_RDWR);
92 if (err < 0) 94 if (err < 0)
93 goto fail; 95 goto fail;
94 96
95 s->hd = hd; 97 s->hd = hd;
98 cur_auth_type = s->auth_state.auth_type;
96 if (http_connect(h, path, hoststr, auth, &location_changed) < 0) 99 if (http_connect(h, path, hoststr, auth, &location_changed) < 0)
97 goto fail; 100 goto fail;
101 if (s->http_code == 401) {
102 if (cur_auth_type == HTTP_AUTH_NONE && s->auth_state.auth_type != HTTP_AUTH_NONE) {
103 url_close(hd);
104 goto redo;
105 } else
106 goto fail;
107 }
98 if ((s->http_code == 302 || s->http_code == 303) && location_changed == 1) { 108 if ((s->http_code == 302 || s->http_code == 303) && location_changed == 1) {
99 /* url moved, get next */ 109 /* url moved, get next */
100 url_close(hd); 110 url_close(hd);
101 if (redirects++ >= MAX_REDIRECTS) 111 if (redirects++ >= MAX_REDIRECTS)
102 return AVERROR(EIO); 112 return AVERROR(EIO);
123 } 133 }
124 h->priv_data = s; 134 h->priv_data = s;
125 s->filesize = -1; 135 s->filesize = -1;
126 s->chunksize = -1; 136 s->chunksize = -1;
127 s->off = 0; 137 s->off = 0;
138 memset(&s->auth_state, 0, sizeof(s->auth_state));
128 av_strlcpy(s->location, uri, URL_SIZE); 139 av_strlcpy(s->location, uri, URL_SIZE);
129 140
130 ret = http_open_cnx(h); 141 ret = http_open_cnx(h);
131 if (ret != 0) 142 if (ret != 0)
132 av_free (s); 143 av_free (s);
191 p++; 202 p++;
192 s->http_code = strtol(p, NULL, 10); 203 s->http_code = strtol(p, NULL, 10);
193 204
194 dprintf(NULL, "http_code=%d\n", s->http_code); 205 dprintf(NULL, "http_code=%d\n", s->http_code);
195 206
196 /* error codes are 4xx and 5xx */ 207 /* error codes are 4xx and 5xx, but regard 401 as a success, so we
197 if (s->http_code >= 400 && s->http_code < 600) 208 * don't abort until all headers have been parsed. */
209 if (s->http_code >= 400 && s->http_code < 600 && s->http_code != 401)
198 return -1; 210 return -1;
199 } else { 211 } else {
200 while (*p != '\0' && *p != ':') 212 while (*p != '\0' && *p != ':')
201 p++; 213 p++;
202 if (*p != ':') 214 if (*p != ':')
223 } 235 }
224 h->is_streamed = 0; /* we _can_ in fact seek */ 236 h->is_streamed = 0; /* we _can_ in fact seek */
225 } else if (!strcmp (tag, "Transfer-Encoding") && !strncasecmp(p, "chunked", 7)) { 237 } else if (!strcmp (tag, "Transfer-Encoding") && !strncasecmp(p, "chunked", 7)) {
226 s->filesize = -1; 238 s->filesize = -1;
227 s->chunksize = 0; 239 s->chunksize = 0;
240 } else if (!strcmp (tag, "WWW-Authenticate")) {
241 ff_http_auth_handle_header(&s->auth_state, tag, p);
242 } else if (!strcmp (tag, "Authentication-Info")) {
243 ff_http_auth_handle_header(&s->auth_state, tag, p);
228 } 244 }
229 } 245 }
230 return 1; 246 return 1;
231 } 247 }
232 248
234 const char *auth, int *new_location) 250 const char *auth, int *new_location)
235 { 251 {
236 HTTPContext *s = h->priv_data; 252 HTTPContext *s = h->priv_data;
237 int post, err; 253 int post, err;
238 char line[1024]; 254 char line[1024];
239 char *auth_b64; 255 char *authstr = NULL;
240 int auth_b64_len = (strlen(auth) + 2) / 3 * 4 + 1;
241 int64_t off = s->off; 256 int64_t off = s->off;
242 257
243 258
244 /* send http header */ 259 /* send http header */
245 post = h->flags & URL_WRONLY; 260 post = h->flags & URL_WRONLY;
246 auth_b64 = av_malloc(auth_b64_len); 261 authstr = ff_http_auth_create_response(&s->auth_state, auth, path,
247 av_base64_encode(auth_b64, auth_b64_len, auth, strlen(auth)); 262 post ? "POST" : "GET");
248 snprintf(s->buffer, sizeof(s->buffer), 263 snprintf(s->buffer, sizeof(s->buffer),
249 "%s %s HTTP/1.1\r\n" 264 "%s %s HTTP/1.1\r\n"
250 "User-Agent: %s\r\n" 265 "User-Agent: %s\r\n"
251 "Accept: */*\r\n" 266 "Accept: */*\r\n"
252 "Range: bytes=%"PRId64"-\r\n" 267 "Range: bytes=%"PRId64"-\r\n"
253 "Host: %s\r\n" 268 "Host: %s\r\n"
254 "Authorization: Basic %s\r\n" 269 "%s"
255 "Connection: close\r\n" 270 "Connection: close\r\n"
256 "%s" 271 "%s"
257 "\r\n", 272 "\r\n",
258 post ? "POST" : "GET", 273 post ? "POST" : "GET",
259 path, 274 path,
260 LIBAVFORMAT_IDENT, 275 LIBAVFORMAT_IDENT,
261 s->off, 276 s->off,
262 hoststr, 277 hoststr,
263 auth_b64, 278 authstr ? authstr : "",
264 post ? "Transfer-Encoding: chunked\r\n" : ""); 279 post ? "Transfer-Encoding: chunked\r\n" : "");
265 280
266 av_freep(&auth_b64); 281 av_freep(&authstr);
267 if (http_write(h, s->buffer, strlen(s->buffer)) < 0) 282 if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
268 return AVERROR(EIO); 283 return AVERROR(EIO);
269 284
270 /* init input buffer */ 285 /* init input buffer */
271 s->buf_ptr = s->buffer; 286 s->buf_ptr = s->buffer;