tested and submitted by (Torsten Spindler <spindler at hbt dot arch dot ethz dot ch>) Originally committed as revision 3381 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -2714,7 +2714,7 @@ static void rtsp_cmd_describe(HTTPContext *c, const char *url) | |||||
| struct sockaddr_in my_addr; | struct sockaddr_in my_addr; | ||||
| /* find which url is asked */ | /* find which url is asked */ | ||||
| url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | |||||
| url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | |||||
| path = path1; | path = path1; | ||||
| if (*path == '/') | if (*path == '/') | ||||
| path++; | path++; | ||||
| @@ -2788,7 +2788,7 @@ static void rtsp_cmd_setup(HTTPContext *c, const char *url, | |||||
| RTSPActionServerSetup setup; | RTSPActionServerSetup setup; | ||||
| /* find which url is asked */ | /* find which url is asked */ | ||||
| url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | |||||
| url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | |||||
| path = path1; | path = path1; | ||||
| if (*path == '/') | if (*path == '/') | ||||
| path++; | path++; | ||||
| @@ -2943,7 +2943,7 @@ static HTTPContext *find_rtp_session_with_url(const char *url, | |||||
| return NULL; | return NULL; | ||||
| /* find which url is asked */ | /* find which url is asked */ | ||||
| url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | |||||
| url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | |||||
| path = path1; | path = path1; | ||||
| if (*path == '/') | if (*path == '/') | ||||
| path++; | path++; | ||||
| @@ -627,6 +627,7 @@ struct in_addr; | |||||
| int resolve_host(struct in_addr *sin_addr, const char *hostname); | int resolve_host(struct in_addr *sin_addr, const char *hostname); | ||||
| void url_split(char *proto, int proto_size, | void url_split(char *proto, int proto_size, | ||||
| char *authorization, int authorization_size, | |||||
| char *hostname, int hostname_size, | char *hostname, int hostname_size, | ||||
| int *port_ptr, | int *port_ptr, | ||||
| char *path, int path_size, | char *path, int path_size, | ||||
| @@ -46,8 +46,10 @@ typedef struct { | |||||
| char location[URL_SIZE]; | char location[URL_SIZE]; | ||||
| } HTTPContext; | } HTTPContext; | ||||
| static int http_connect(URLContext *h, const char *path, const char *hoststr); | |||||
| static int http_connect(URLContext *h, const char *path, const char *hoststr, | |||||
| const char *auth); | |||||
| static int http_write(URLContext *h, uint8_t *buf, int size); | static int http_write(URLContext *h, uint8_t *buf, int size); | ||||
| static char *b64_encode( unsigned char *src ); | |||||
| /* return non zero if error */ | /* return non zero if error */ | ||||
| @@ -55,6 +57,7 @@ static int http_open(URLContext *h, const char *uri, int flags) | |||||
| { | { | ||||
| const char *path, *proxy_path; | const char *path, *proxy_path; | ||||
| char hostname[1024], hoststr[1024]; | char hostname[1024], hoststr[1024]; | ||||
| char auth[1024]; | |||||
| char path1[1024]; | char path1[1024]; | ||||
| char buf[1024]; | char buf[1024]; | ||||
| int port, use_proxy, err; | int port, use_proxy, err; | ||||
| @@ -76,7 +79,7 @@ static int http_open(URLContext *h, const char *uri, int flags) | |||||
| /* fill the dest addr */ | /* fill the dest addr */ | ||||
| redo: | redo: | ||||
| /* needed in any case to build the host string */ | /* needed in any case to build the host string */ | ||||
| url_split(NULL, 0, hostname, sizeof(hostname), &port, | |||||
| url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, | |||||
| path1, sizeof(path1), uri); | path1, sizeof(path1), uri); | ||||
| if (port > 0) { | if (port > 0) { | ||||
| snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port); | snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port); | ||||
| @@ -85,7 +88,7 @@ static int http_open(URLContext *h, const char *uri, int flags) | |||||
| } | } | ||||
| if (use_proxy) { | if (use_proxy) { | ||||
| url_split(NULL, 0, hostname, sizeof(hostname), &port, | |||||
| url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, | |||||
| NULL, 0, proxy_path); | NULL, 0, proxy_path); | ||||
| path = uri; | path = uri; | ||||
| } else { | } else { | ||||
| @@ -103,7 +106,7 @@ static int http_open(URLContext *h, const char *uri, int flags) | |||||
| goto fail; | goto fail; | ||||
| s->hd = hd; | s->hd = hd; | ||||
| if (http_connect(h, path, hoststr) < 0) | |||||
| if (http_connect(h, path, hoststr, auth) < 0) | |||||
| goto fail; | goto fail; | ||||
| if (s->http_code == 303 && s->location[0] != '\0') { | if (s->http_code == 303 && s->location[0] != '\0') { | ||||
| /* url moved, get next */ | /* url moved, get next */ | ||||
| @@ -172,7 +175,8 @@ static int process_line(HTTPContext *s, char *line, int line_count) | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| static int http_connect(URLContext *h, const char *path, const char *hoststr) | |||||
| static int http_connect(URLContext *h, const char *path, const char *hoststr, | |||||
| const char *auth) | |||||
| { | { | ||||
| HTTPContext *s = h->priv_data; | HTTPContext *s = h->priv_data; | ||||
| int post, err, ch; | int post, err, ch; | ||||
| @@ -187,11 +191,13 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr) | |||||
| "User-Agent: %s\r\n" | "User-Agent: %s\r\n" | ||||
| "Accept: */*\r\n" | "Accept: */*\r\n" | ||||
| "Host: %s\r\n" | "Host: %s\r\n" | ||||
| "Authorization: Basic %s\r\n" | |||||
| "\r\n", | "\r\n", | ||||
| post ? "POST" : "GET", | post ? "POST" : "GET", | ||||
| path, | path, | ||||
| LIBAVFORMAT_IDENT, | LIBAVFORMAT_IDENT, | ||||
| hoststr); | |||||
| hoststr, | |||||
| b64_encode(auth)); | |||||
| if (http_write(h, s->buffer, strlen(s->buffer)) < 0) | if (http_write(h, s->buffer, strlen(s->buffer)) < 0) | ||||
| return AVERROR_IO; | return AVERROR_IO; | ||||
| @@ -277,3 +283,46 @@ URLProtocol http_protocol = { | |||||
| http_close, | http_close, | ||||
| }; | }; | ||||
| /***************************************************************************** | |||||
| * b64_encode: stolen from VLC's http.c | |||||
| *****************************************************************************/ | |||||
| static char *b64_encode( unsigned char *src ) | |||||
| { | |||||
| static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||||
| char *dst = av_malloc( strlen( src ) * 4 / 3 + 12 ); | |||||
| char *ret = dst; | |||||
| unsigned i_bits = 0; | |||||
| unsigned i_shift = 0; | |||||
| for( ;; ) | |||||
| { | |||||
| if( *src ) | |||||
| { | |||||
| i_bits = ( i_bits << 8 )|( *src++ ); | |||||
| i_shift += 8; | |||||
| } | |||||
| else if( i_shift > 0 ) | |||||
| { | |||||
| i_bits <<= 6 - i_shift; | |||||
| i_shift = 6; | |||||
| } | |||||
| else | |||||
| { | |||||
| *dst++ = '='; | |||||
| break; | |||||
| } | |||||
| while( i_shift >= 6 ) | |||||
| { | |||||
| i_shift -= 6; | |||||
| *dst++ = b64[(i_bits >> i_shift)&0x3f]; | |||||
| } | |||||
| } | |||||
| *dst++ = '\0'; | |||||
| return ret; | |||||
| } | |||||
| @@ -57,7 +57,7 @@ int rtp_set_remote_url(URLContext *h, const char *uri) | |||||
| char buf[1024]; | char buf[1024]; | ||||
| char path[1024]; | char path[1024]; | ||||
| url_split(NULL, 0, hostname, sizeof(hostname), &port, | |||||
| url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |||||
| path, sizeof(path), uri); | path, sizeof(path), uri); | ||||
| snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); | snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); | ||||
| @@ -122,7 +122,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) | |||||
| return -ENOMEM; | return -ENOMEM; | ||||
| h->priv_data = s; | h->priv_data = s; | ||||
| url_split(NULL, 0, hostname, sizeof(hostname), &port, | |||||
| url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |||||
| path, sizeof(path), uri); | path, sizeof(path), uri); | ||||
| /* extract parameters */ | /* extract parameters */ | ||||
| is_multicast = 0; | is_multicast = 0; | ||||
| @@ -339,7 +339,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, | |||||
| rtsp_st = st->priv_data; | rtsp_st = st->priv_data; | ||||
| /* XXX: may need to add full url resolution */ | /* XXX: may need to add full url resolution */ | ||||
| url_split(proto, sizeof(proto), NULL, 0, NULL, NULL, 0, p); | |||||
| url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p); | |||||
| if (proto[0] == '\0') { | if (proto[0] == '\0') { | ||||
| /* relative control URL */ | /* relative control URL */ | ||||
| pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/"); | pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/"); | ||||
| @@ -723,7 +723,7 @@ static int rtsp_read_header(AVFormatContext *s, | |||||
| AVStream *st; | AVStream *st; | ||||
| /* extract hostname and port */ | /* extract hostname and port */ | ||||
| url_split(NULL, 0, | |||||
| url_split(NULL, 0, NULL, 0, | |||||
| host, sizeof(host), &port, path, sizeof(path), s->filename); | host, sizeof(host), &port, path, sizeof(path), s->filename); | ||||
| if (port < 0) | if (port < 0) | ||||
| port = RTSP_DEFAULT_PORT; | port = RTSP_DEFAULT_PORT; | ||||
| @@ -63,25 +63,18 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||||
| int fd_max, ret; | int fd_max, ret; | ||||
| struct timeval tv; | struct timeval tv; | ||||
| socklen_t optlen; | socklen_t optlen; | ||||
| char proto[1024],path[1024],tmp[1024]; // PETR: protocol and path strings | |||||
| url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), | |||||
| &port, path, sizeof(path), uri); // PETR: use url_split | |||||
| if (strcmp(proto,"tcp")) goto fail; // PETR: check protocol | |||||
| if ((q = strchr(hostname,'@'))) { strcpy(tmp,q+1); strcpy(hostname,tmp); } // PETR: take only the part after '@' for tcp protocol | |||||
| s = av_malloc(sizeof(TCPContext)); | s = av_malloc(sizeof(TCPContext)); | ||||
| if (!s) | if (!s) | ||||
| return -ENOMEM; | return -ENOMEM; | ||||
| h->priv_data = s; | h->priv_data = s; | ||||
| p = uri; | |||||
| if (!strstart(p, "tcp://", &p)) | |||||
| goto fail; | |||||
| q = hostname; | |||||
| while (*p != ':' && *p != '/' && *p != '\0') { | |||||
| if ((q - hostname) < sizeof(hostname) - 1) | |||||
| *q++ = *p; | |||||
| p++; | |||||
| } | |||||
| *q = '\0'; | |||||
| if (*p != ':') | |||||
| goto fail; | |||||
| p++; | |||||
| port = strtoul(p, (char **)&p, 10); | |||||
| if (port <= 0 || port >= 65536) | if (port <= 0 || port >= 65536) | ||||
| goto fail; | goto fail; | ||||
| @@ -60,7 +60,7 @@ int udp_set_remote_url(URLContext *h, const char *uri) | |||||
| char hostname[256]; | char hostname[256]; | ||||
| int port; | int port; | ||||
| url_split(NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); | |||||
| url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); | |||||
| /* set the destination address */ | /* set the destination address */ | ||||
| if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0) | if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0) | ||||
| @@ -132,7 +132,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) | |||||
| } | } | ||||
| /* fill the dest addr */ | /* fill the dest addr */ | ||||
| url_split(NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); | |||||
| url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); | |||||
| /* XXX: fix url_split */ | /* XXX: fix url_split */ | ||||
| if (hostname[0] == '\0' || hostname[0] == '?') { | if (hostname[0] == '\0' || hostname[0] == '?') { | ||||
| @@ -2499,6 +2499,7 @@ void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload) | |||||
| } | } | ||||
| void url_split(char *proto, int proto_size, | void url_split(char *proto, int proto_size, | ||||
| char *authorization, int authorization_size, | |||||
| char *hostname, int hostname_size, | char *hostname, int hostname_size, | ||||
| int *port_ptr, | int *port_ptr, | ||||
| char *path, int path_size, | char *path, int path_size, | ||||
| @@ -2519,6 +2520,8 @@ void url_split(char *proto, int proto_size, | |||||
| } | } | ||||
| if (proto_size > 0) | if (proto_size > 0) | ||||
| *q = '\0'; | *q = '\0'; | ||||
| if (authorization_size > 0) | |||||
| authorization[0] = '\0'; | |||||
| if (*p == '\0') { | if (*p == '\0') { | ||||
| if (proto_size > 0) | if (proto_size > 0) | ||||
| proto[0] = '\0'; | proto[0] = '\0'; | ||||
| @@ -2526,15 +2529,32 @@ void url_split(char *proto, int proto_size, | |||||
| hostname[0] = '\0'; | hostname[0] = '\0'; | ||||
| p = url; | p = url; | ||||
| } else { | } else { | ||||
| char *at,*slash; // PETR: position of '@' character and '/' character | |||||
| p++; | p++; | ||||
| if (*p == '/') | if (*p == '/') | ||||
| p++; | p++; | ||||
| if (*p == '/') | if (*p == '/') | ||||
| p++; | p++; | ||||
| q = hostname; | |||||
| while (*p != ':' && *p != '/' && *p != '?' && *p != '\0') { | |||||
| if ((q - hostname) < hostname_size - 1) | |||||
| at = strchr(p,'@'); // PETR: get the position of '@' | |||||
| slash = strchr(p,'/'); // PETR: get position of '/' - end of hostname | |||||
| if (at && slash && at > slash) at = NULL; // PETR: not interested in '@' behind '/' | |||||
| q = at ? authorization : hostname; // PETR: if '@' exists starting with auth. | |||||
| while ((at || *p != ':') && *p != '/' && *p != '?' && *p != '\0') { // PETR: | |||||
| if (*p == '@') { // PETR: passed '@' | |||||
| if (authorization_size > 0) | |||||
| *q = '\0'; | |||||
| q = hostname; | |||||
| at = NULL; | |||||
| } else if (!at) { // PETR: hostname | |||||
| if ((q - hostname) < hostname_size - 1) | |||||
| *q++ = *p; | |||||
| } else { | |||||
| if ((q - authorization) < authorization_size - 1) | |||||
| *q++ = *p; | *q++ = *p; | ||||
| } | |||||
| p++; | p++; | ||||
| } | } | ||||
| if (hostname_size > 0) | if (hostname_size > 0) | ||||