From 6964d510e8328d04196b549f0e7149efd076b7b4 Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Tue, 8 Jun 2010 10:26:16 +0000 Subject: [PATCH] Add the capability to write custom HTTP headers Patch by Josh Allmann, joshua dot allmann at gmail Originally committed as revision 23526 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/http.c | 56 +++++++++++++++++++++++++++++++++++++--------- libavformat/http.h | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 libavformat/http.h diff --git a/libavformat/http.c b/libavformat/http.c index 855c67a155..0b4b57077a 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -25,6 +25,7 @@ #include #include "internal.h" #include "network.h" +#include "http.h" #include "os_support.h" #include "httpauth.h" @@ -46,12 +47,23 @@ typedef struct { char location[URL_SIZE]; HTTPAuthState auth_state; int init; + unsigned char headers[BUFFER_SIZE]; } HTTPContext; static int http_connect(URLContext *h, const char *path, const char *hoststr, const char *auth, int *new_location); static int http_write(URLContext *h, const uint8_t *buf, int size); +void ff_http_set_headers(URLContext *h, const char *headers) +{ + HTTPContext *s = h->priv_data; + int len = strlen(headers); + + if (len && strcmp("\r\n", headers + len - 2)) + av_log(NULL, AV_LOG_ERROR, "No trailing CRLF found in HTTP header.\n"); + + av_strlcpy(s->headers, headers, sizeof(s->headers)); +} /* return non zero if error */ static int http_open_cnx(URLContext *h) @@ -137,6 +149,7 @@ static int http_open(URLContext *h, const char *uri, int flags) s->chunksize = -1; s->off = 0; s->init = 0; + *s->headers = '\0'; memset(&s->auth_state, 0, sizeof(s->auth_state)); av_strlcpy(s->location, uri, URL_SIZE); @@ -245,37 +258,60 @@ static int process_line(URLContext *h, char *line, int line_count, return 1; } +static inline int has_header(const char *str, const char *header) +{ + /* header + 2 to skip over CRLF prefix. (make sure you have one!) */ + return av_stristart(str, header + 2, NULL) || av_stristr(str, header); +} + static int http_connect(URLContext *h, const char *path, const char *hoststr, const char *auth, int *new_location) { HTTPContext *s = h->priv_data; int post, err; char line[1024]; + char headers[1024]; char *authstr = NULL; int64_t off = s->off; + int len = 0; /* send http header */ post = h->flags & URL_WRONLY; authstr = ff_http_auth_create_response(&s->auth_state, auth, path, post ? "POST" : "GET"); + + /* set default headers if needed */ + if (!has_header(s->headers, "\r\nUser-Agent: ")) + len += av_strlcatf(headers + len, sizeof(headers) - len, + "User-Agent: %s\r\n", LIBAVFORMAT_IDENT); + if (!has_header(s->headers, "\r\nAccept: ")) + len += av_strlcpy(headers + len, "Accept: */*\r\n", + sizeof(headers) - len); + if (!has_header(s->headers, "\r\nRange: ")) + len += av_strlcatf(headers + len, sizeof(headers) - len, + "Range: bytes=%"PRId64"\r\n", s->off); + if (!has_header(s->headers, "\r\nConnection: ")) + len += av_strlcpy(headers + len, "Connection: close\r\n", + sizeof(headers)-len); + if (!has_header(s->headers, "\r\nHost: ")) + len += av_strlcatf(headers + len, sizeof(headers) - len, + "Host: %s\r\n", hoststr); + + /* now add in custom headers */ + av_strlcpy(headers+len, s->headers, sizeof(headers)-len); + snprintf(s->buffer, sizeof(s->buffer), "%s %s HTTP/1.1\r\n" - "User-Agent: %s\r\n" - "Accept: */*\r\n" - "Range: bytes=%"PRId64"-\r\n" - "Host: %s\r\n" "%s" - "Connection: close\r\n" + "%s" "%s" "\r\n", post ? "POST" : "GET", path, - LIBAVFORMAT_IDENT, - s->off, - hoststr, - authstr ? authstr : "", - post ? "Transfer-Encoding: chunked\r\n" : ""); + post ? "Transfer-Encoding: chunked\r\n" : "", + headers, + authstr ? authstr : ""); av_freep(&authstr); if (http_write(h, s->buffer, strlen(s->buffer)) < 0) diff --git a/libavformat/http.h b/libavformat/http.h new file mode 100644 index 0000000000..6f0566d7d8 --- /dev/null +++ b/libavformat/http.h @@ -0,0 +1,42 @@ +/* + * HTTP definitions + * Copyright (c) 2010 Josh Allmann + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVFORMAT_HTTP_H +#define AVFORMAT_HTTP_H + +/** + * Sets custom HTTP headers. + * A trailing CRLF ("\r\n") is required for custom headers. + * Passing in an empty header string ("\0") will reset to defaults. + * + * The following headers can be overriden by custom values, + * otherwise they will be set to their defaults. + * -User-Agent + * -Accept + * -Range + * -Host + * -Connection + * + * @param h URL context for this HTTP connection + * @param headers the custom headers to set + */ +void ff_http_set_headers(URLContext *h, const char *headers); + +#endif /* AVFORMAT_HTTP_H */