Mercurial > mplayer.hg
annotate stream/http.c @ 25564:9f8df9433c25
Add HAVE_SOCKLEN_T to config.h for FFmpeg
Needed to fix compilation after recent FFmpeg changes. It's now always
set to true without any tests. I don't expect this to cause problems
as common systems will have the type and the FFmpeg demuxers which
would use it are not compiled under MPlayer (compilation was broken
because the type was redefined in a header).
author | uau |
---|---|
date | Thu, 03 Jan 2008 01:44:58 +0000 |
parents | c8d5c8f0b9ef |
children | c7f41f9e2eb8 |
rev | line source |
---|---|
902 | 1 /* |
2 * HTTP Helper | |
3 * by Bertrand Baudet <bertrand_baudet@yahoo.com> | |
4 * (C) 2001, MPlayer team. | |
5 */ | |
6 | |
15614
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
7 #include "config.h" |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
8 |
870 | 9 #include <stdio.h> |
10 #include <stdlib.h> | |
11 #include <string.h> | |
15585 | 12 #include <unistd.h> |
870 | 13 |
15614
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
14 #ifndef HAVE_WINSOCK2 |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
15 #define closesocket close |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
16 #else |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
17 #include <winsock2.h> |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
18 #include <ws2tcpip.h> |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
19 #endif |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
20 |
870 | 21 #include "http.h" |
4816
f1dea39a50bb
Fixed the http response parser when the http header only has the HTTP
bertrand
parents:
4311
diff
changeset
|
22 #include "url.h" |
5915 | 23 #include "mp_msg.h" |
870 | 24 |
15585 | 25 #include "stream.h" |
19312
ab8d6b6deb63
proper inclusion of demuxer.h (including libmpdemux in Makefile only was to make previous split easier)
ben
parents:
19271
diff
changeset
|
26 #include "libmpdemux/demuxer.h" |
15585 | 27 #include "network.h" |
28 #include "help_mp.h" | |
29 | |
30 | |
25246 | 31 extern const mime_struct_t mime_type_table[]; |
15585 | 32 extern int stream_cache_size; |
33 extern int network_bandwidth; | |
34 | |
35 extern int http_seek(stream_t *stream, off_t pos); | |
36 | |
16013 | 37 typedef struct { |
38 unsigned metaint; | |
39 unsigned metapos; | |
40 int is_ultravox; | |
41 } scast_data_t; | |
42 | |
43 /** | |
44 * \brief first read any data from sc->buffer then from fd | |
45 * \param fd file descriptor to read data from | |
46 * \param buffer buffer to read into | |
47 * \param len how many bytes to read | |
48 * \param sc streaming control containing buffer to read from first | |
49 * \return len unless there is a read error or eof | |
50 */ | |
51 static unsigned my_read(int fd, char *buffer, int len, streaming_ctrl_t *sc) { | |
52 unsigned pos = 0; | |
53 unsigned cp_len = sc->buffer_size - sc->buffer_pos; | |
54 if (cp_len > len) | |
55 cp_len = len; | |
56 memcpy(buffer, &sc->buffer[sc->buffer_pos], cp_len); | |
57 sc->buffer_pos += cp_len; | |
58 pos += cp_len; | |
59 while (pos < len) { | |
16070 | 60 int ret = recv(fd, &buffer[pos], len - pos, 0); |
16013 | 61 if (ret <= 0) |
62 break; | |
63 pos += ret; | |
64 } | |
65 return pos; | |
66 } | |
67 | |
16032 | 68 /** |
69 * \brief read and process (i.e. discard *g*) a block of ultravox metadata | |
70 * \param fd file descriptor to read from | |
71 * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd | |
72 * \return number of real data before next metadata block starts or 0 on error | |
73 */ | |
16013 | 74 static unsigned uvox_meta_read(int fd, streaming_ctrl_t *sc) { |
75 unsigned metaint; | |
16070 | 76 unsigned char info[6] = {0, 0, 0, 0, 0, 0}; |
77 int info_read; | |
16013 | 78 do { |
16070 | 79 info_read = my_read(fd, info, 1, sc); |
16013 | 80 if (info[0] == 0x00) |
16070 | 81 info_read = my_read(fd, info, 6, sc); |
16013 | 82 else |
16070 | 83 info_read += my_read(fd, &info[1], 5, sc); |
84 if (info_read != 6) // read error or eof | |
85 return 0; | |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
86 // sync byte and reserved flags |
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
87 if (info[0] != 0x5a || (info[1] & 0xfc) != 0x00) { |
16013 | 88 mp_msg(MSGT_DEMUXER, MSGL_ERR, "Invalid or unknown uvox metadata\n"); |
89 return 0; | |
90 } | |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
91 if (info[1] & 0x01) |
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
92 mp_msg(MSGT_DEMUXER, MSGL_WARN, "Encrypted ultravox data\n"); |
16013 | 93 metaint = info[4] << 8 | info[5]; |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
94 if ((info[3] & 0xf) < 0x07) { // discard any metadata nonsense |
16013 | 95 char *metabuf = malloc(metaint); |
96 my_read(fd, metabuf, metaint, sc); | |
97 free(metabuf); | |
98 } | |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
99 } while ((info[3] & 0xf) < 0x07); |
16013 | 100 return metaint; |
101 } | |
102 | |
103 /** | |
104 * \brief read one scast meta data entry and print it | |
16032 | 105 * \param fd file descriptor to read from |
106 * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd | |
16013 | 107 */ |
108 static void scast_meta_read(int fd, streaming_ctrl_t *sc) { | |
109 unsigned char tmp = 0; | |
110 unsigned metalen; | |
111 my_read(fd, &tmp, 1, sc); | |
112 metalen = tmp * 16; | |
113 if (metalen > 0) { | |
18879 | 114 char *info = malloc(metalen + 1); |
16013 | 115 unsigned nlen = my_read(fd, info, metalen, sc); |
116 info[nlen] = 0; | |
117 mp_msg(MSGT_DEMUXER, MSGL_INFO, "\nICY Info: %s\n", info); | |
118 free(info); | |
119 } | |
120 } | |
121 | |
16032 | 122 /** |
123 * \brief read data from scast/ultravox stream without any metadata | |
124 * \param fd file descriptor to read from | |
125 * \param buffer buffer to read data into | |
126 * \param size number of bytes to read | |
127 * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd | |
128 */ | |
16013 | 129 static int scast_streaming_read(int fd, char *buffer, int size, |
130 streaming_ctrl_t *sc) { | |
131 scast_data_t *sd = (scast_data_t *)sc->data; | |
132 unsigned block, ret; | |
133 unsigned done = 0; | |
134 | |
135 // first read remaining data up to next metadata | |
136 block = sd->metaint - sd->metapos; | |
137 if (block > size) | |
138 block = size; | |
139 ret = my_read(fd, buffer, block, sc); | |
140 sd->metapos += ret; | |
141 done += ret; | |
142 if (ret != block) // read problems or eof | |
143 size = done; | |
144 | |
145 while (done < size) { // now comes the metadata | |
146 if (sd->is_ultravox) | |
16070 | 147 { |
16013 | 148 sd->metaint = uvox_meta_read(fd, sc); |
16070 | 149 if (!sd->metaint) |
150 size = done; | |
151 } | |
16013 | 152 else |
153 scast_meta_read(fd, sc); // read and display metadata | |
154 sd->metapos = 0; | |
155 block = size - done; | |
156 if (block > sd->metaint) | |
157 block = sd->metaint; | |
158 ret = my_read(fd, &buffer[done], block, sc); | |
159 sd->metapos += ret; | |
160 done += ret; | |
161 if (ret != block) // read problems or eof | |
162 size = done; | |
163 } | |
164 return done; | |
165 } | |
166 | |
167 static int scast_streaming_start(stream_t *stream) { | |
168 int metaint; | |
169 scast_data_t *scast_data; | |
170 HTTP_header_t *http_hdr = stream->streaming_ctrl->data; | |
16070 | 171 int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; |
16013 | 172 if (!stream || stream->fd < 0 || !http_hdr) |
173 return -1; | |
174 if (is_ultravox) | |
175 metaint = 0; | |
176 else { | |
177 metaint = atoi(http_get_field(http_hdr, "Icy-MetaInt")); | |
178 if (metaint <= 0) | |
179 return -1; | |
180 } | |
181 stream->streaming_ctrl->buffer = malloc(http_hdr->body_size); | |
182 stream->streaming_ctrl->buffer_size = http_hdr->body_size; | |
183 stream->streaming_ctrl->buffer_pos = 0; | |
184 memcpy(stream->streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size); | |
185 scast_data = malloc(sizeof(scast_data_t)); | |
186 scast_data->metaint = metaint; | |
187 scast_data->metapos = 0; | |
188 scast_data->is_ultravox = is_ultravox; | |
189 http_free(http_hdr); | |
190 stream->streaming_ctrl->data = scast_data; | |
191 stream->streaming_ctrl->streaming_read = scast_streaming_read; | |
192 stream->streaming_ctrl->streaming_seek = NULL; | |
193 stream->streaming_ctrl->prebuffer_size = 64 * 1024; // 64 KBytes | |
194 stream->streaming_ctrl->buffering = 1; | |
195 stream->streaming_ctrl->status = streaming_playing_e; | |
196 return 0; | |
197 } | |
198 | |
15585 | 199 static int nop_streaming_start( stream_t *stream ) { |
200 HTTP_header_t *http_hdr = NULL; | |
201 char *next_url=NULL; | |
202 URL_t *rd_url=NULL; | |
203 int fd,ret; | |
204 if( stream==NULL ) return -1; | |
205 | |
206 fd = stream->fd; | |
207 if( fd<0 ) { | |
208 fd = http_send_request( stream->streaming_ctrl->url, 0 ); | |
209 if( fd<0 ) return -1; | |
210 http_hdr = http_read_response( fd ); | |
211 if( http_hdr==NULL ) return -1; | |
212 | |
213 switch( http_hdr->status_code ) { | |
214 case 200: // OK | |
215 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") ); | |
216 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") ); | |
217 if( http_hdr->body_size>0 ) { | |
218 if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { | |
219 http_free( http_hdr ); | |
220 return -1; | |
221 } | |
222 } | |
223 break; | |
224 // Redirect | |
225 case 301: // Permanently | |
226 case 302: // Temporarily | |
19459
6dad4b1efb82
Handle 303 (See Other) redirect, part of a patch by Benjamin Zores (ben at geexbox org)
reimar
parents:
19312
diff
changeset
|
227 case 303: // See Other |
15585 | 228 ret=-1; |
229 next_url = http_get_field( http_hdr, "Location" ); | |
230 | |
231 if (next_url != NULL) | |
232 rd_url=url_new(next_url); | |
233 | |
234 if (next_url != NULL && rd_url != NULL) { | |
235 mp_msg(MSGT_NETWORK,MSGL_STATUS,"Redirected: Using this url instead %s\n",next_url); | |
236 stream->streaming_ctrl->url=check4proxies(rd_url); | |
237 ret=nop_streaming_start(stream); //recursively get streaming started | |
238 } else { | |
239 mp_msg(MSGT_NETWORK,MSGL_ERR,"Redirection failed\n"); | |
240 closesocket( fd ); | |
241 fd = -1; | |
242 } | |
243 return ret; | |
244 break; | |
245 case 401: //Authorization required | |
246 case 403: //Forbidden | |
247 case 404: //Not found | |
248 case 500: //Server Error | |
249 default: | |
250 mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned code %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); | |
251 closesocket( fd ); | |
252 fd = -1; | |
253 return -1; | |
254 break; | |
255 } | |
256 stream->fd = fd; | |
257 } else { | |
258 http_hdr = (HTTP_header_t*)stream->streaming_ctrl->data; | |
259 if( http_hdr->body_size>0 ) { | |
260 if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { | |
261 http_free( http_hdr ); | |
262 stream->streaming_ctrl->data = NULL; | |
263 return -1; | |
264 } | |
265 } | |
266 } | |
267 | |
268 if( http_hdr ) { | |
269 http_free( http_hdr ); | |
270 stream->streaming_ctrl->data = NULL; | |
271 } | |
272 | |
273 stream->streaming_ctrl->streaming_read = nop_streaming_read; | |
274 stream->streaming_ctrl->streaming_seek = nop_streaming_seek; | |
275 stream->streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes | |
276 stream->streaming_ctrl->buffering = 1; | |
277 stream->streaming_ctrl->status = streaming_playing_e; | |
278 return 0; | |
279 } | |
280 | |
870 | 281 HTTP_header_t * |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
16948
diff
changeset
|
282 http_new_header(void) { |
870 | 283 HTTP_header_t *http_hdr; |
284 | |
18879 | 285 http_hdr = malloc(sizeof(HTTP_header_t)); |
870 | 286 if( http_hdr==NULL ) return NULL; |
287 memset( http_hdr, 0, sizeof(HTTP_header_t) ); | |
288 | |
289 return http_hdr; | |
290 } | |
291 | |
292 void | |
293 http_free( HTTP_header_t *http_hdr ) { | |
3039 | 294 HTTP_field_t *field, *field2free; |
870 | 295 if( http_hdr==NULL ) return; |
296 if( http_hdr->protocol!=NULL ) free( http_hdr->protocol ); | |
297 if( http_hdr->uri!=NULL ) free( http_hdr->uri ); | |
298 if( http_hdr->reason_phrase!=NULL ) free( http_hdr->reason_phrase ); | |
299 if( http_hdr->field_search!=NULL ) free( http_hdr->field_search ); | |
902 | 300 if( http_hdr->method!=NULL ) free( http_hdr->method ); |
301 if( http_hdr->buffer!=NULL ) free( http_hdr->buffer ); | |
3039 | 302 field = http_hdr->first_field; |
303 while( field!=NULL ) { | |
304 field2free = field; | |
14460 | 305 if (field->field_name) |
306 free(field->field_name); | |
3039 | 307 field = field->next; |
308 free( field2free ); | |
309 } | |
870 | 310 free( http_hdr ); |
3039 | 311 http_hdr = NULL; |
870 | 312 } |
313 | |
902 | 314 int |
315 http_response_append( HTTP_header_t *http_hdr, char *response, int length ) { | |
1027 | 316 if( http_hdr==NULL || response==NULL || length<0 ) return -1; |
7304
7da2c2a68547
Check if realloc failed on http_hdr->buffer instead of ptr in http_response_append,
bertrand
parents:
7293
diff
changeset
|
317 |
18558
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
318 if( (unsigned)length > SIZE_MAX - http_hdr->buffer_size - 1) { |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
319 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Bad size in memory (re)allocation\n"); |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
320 return -1; |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
321 } |
7293 | 322 http_hdr->buffer = (char*)realloc( http_hdr->buffer, http_hdr->buffer_size+length+1 ); |
7304
7da2c2a68547
Check if realloc failed on http_hdr->buffer instead of ptr in http_response_append,
bertrand
parents:
7293
diff
changeset
|
323 if( http_hdr->buffer==NULL ) { |
7293 | 324 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory (re)allocation failed\n"); |
902 | 325 return -1; |
326 } | |
7293 | 327 memcpy( http_hdr->buffer+http_hdr->buffer_size, response, length ); |
328 http_hdr->buffer_size += length; | |
329 http_hdr->buffer[http_hdr->buffer_size]=0; // close the string! | |
902 | 330 return http_hdr->buffer_size; |
331 } | |
332 | |
333 int | |
2489
0ecc1b4f7cf8
Added ASF http server streaming (Not mms streaming).
bertrand
parents:
2310
diff
changeset
|
334 http_is_header_entire( HTTP_header_t *http_hdr ) { |
902 | 335 if( http_hdr==NULL ) return -1; |
7293 | 336 if( http_hdr->buffer==NULL ) return 0; // empty |
337 | |
3784 | 338 if( strstr(http_hdr->buffer, "\r\n\r\n")==NULL && |
339 strstr(http_hdr->buffer, "\n\n")==NULL ) return 0; | |
340 return 1; | |
902 | 341 } |
342 | |
343 int | |
344 http_response_parse( HTTP_header_t *http_hdr ) { | |
870 | 345 char *hdr_ptr, *ptr; |
346 char *field=NULL; | |
18558
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
347 int pos_hdr_sep, hdr_sep_len; |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
348 size_t len; |
902 | 349 if( http_hdr==NULL ) return -1; |
350 if( http_hdr->is_parsed ) return 0; | |
870 | 351 |
352 // Get the protocol | |
902 | 353 hdr_ptr = strstr( http_hdr->buffer, " " ); |
870 | 354 if( hdr_ptr==NULL ) { |
5915 | 355 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. No space separator found.\n"); |
902 | 356 return -1; |
870 | 357 } |
902 | 358 len = hdr_ptr-http_hdr->buffer; |
18879 | 359 http_hdr->protocol = malloc(len+1); |
870 | 360 if( http_hdr->protocol==NULL ) { |
5915 | 361 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
902 | 362 return -1; |
870 | 363 } |
902 | 364 strncpy( http_hdr->protocol, http_hdr->buffer, len ); |
365 http_hdr->protocol[len]='\0'; | |
870 | 366 if( !strncasecmp( http_hdr->protocol, "HTTP", 4) ) { |
367 if( sscanf( http_hdr->protocol+5,"1.%d", &(http_hdr->http_minor_version) )!=1 ) { | |
5915 | 368 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get HTTP minor version.\n"); |
902 | 369 return -1; |
870 | 370 } |
371 } | |
372 | |
373 // Get the status code | |
374 if( sscanf( ++hdr_ptr, "%d", &(http_hdr->status_code) )!=1 ) { | |
5915 | 375 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get status code.\n"); |
902 | 376 return -1; |
870 | 377 } |
378 hdr_ptr += 4; | |
379 | |
380 // Get the reason phrase | |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
381 ptr = strstr( hdr_ptr, "\n" ); |
870 | 382 if( hdr_ptr==NULL ) { |
5915 | 383 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get the reason phrase.\n"); |
902 | 384 return -1; |
870 | 385 } |
386 len = ptr-hdr_ptr; | |
18879 | 387 http_hdr->reason_phrase = malloc(len+1); |
870 | 388 if( http_hdr->reason_phrase==NULL ) { |
5915 | 389 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
902 | 390 return -1; |
870 | 391 } |
392 strncpy( http_hdr->reason_phrase, hdr_ptr, len ); | |
4311 | 393 if( http_hdr->reason_phrase[len-1]=='\r' ) { |
394 len--; | |
395 } | |
870 | 396 http_hdr->reason_phrase[len]='\0'; |
397 | |
398 // Set the position of the header separator: \r\n\r\n | |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
399 hdr_sep_len = 4; |
902 | 400 ptr = strstr( http_hdr->buffer, "\r\n\r\n" ); |
870 | 401 if( ptr==NULL ) { |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
402 ptr = strstr( http_hdr->buffer, "\n\n" ); |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
403 if( ptr==NULL ) { |
5915 | 404 mp_msg(MSGT_NETWORK,MSGL_ERR,"Header may be incomplete. No CRLF CRLF found.\n"); |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
405 return -1; |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
406 } |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
407 hdr_sep_len = 2; |
870 | 408 } |
902 | 409 pos_hdr_sep = ptr-http_hdr->buffer; |
870 | 410 |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
411 // Point to the first line after the method line. |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
412 hdr_ptr = strstr( http_hdr->buffer, "\n" )+1; |
870 | 413 do { |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
414 ptr = hdr_ptr; |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
415 while( *ptr!='\r' && *ptr!='\n' ) ptr++; |
870 | 416 len = ptr-hdr_ptr; |
4816
f1dea39a50bb
Fixed the http response parser when the http header only has the HTTP
bertrand
parents:
4311
diff
changeset
|
417 if( len==0 ) break; |
870 | 418 field = (char*)realloc(field, len+1); |
419 if( field==NULL ) { | |
5915 | 420 mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); |
902 | 421 return -1; |
870 | 422 } |
423 strncpy( field, hdr_ptr, len ); | |
424 field[len]='\0'; | |
425 http_set_field( http_hdr, field ); | |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
426 hdr_ptr = ptr+((*ptr=='\r')?2:1); |
902 | 427 } while( hdr_ptr<(http_hdr->buffer+pos_hdr_sep) ); |
870 | 428 |
429 if( field!=NULL ) free( field ); | |
430 | |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
431 if( pos_hdr_sep+hdr_sep_len<http_hdr->buffer_size ) { |
870 | 432 // Response has data! |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
433 http_hdr->body = http_hdr->buffer+pos_hdr_sep+hdr_sep_len; |
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
434 http_hdr->body_size = http_hdr->buffer_size-(pos_hdr_sep+hdr_sep_len); |
870 | 435 } |
436 | |
902 | 437 http_hdr->is_parsed = 1; |
438 return 0; | |
870 | 439 } |
440 | |
441 char * | |
902 | 442 http_build_request( HTTP_header_t *http_hdr ) { |
3497 | 443 char *ptr, *uri=NULL; |
902 | 444 int len; |
3039 | 445 HTTP_field_t *field; |
870 | 446 if( http_hdr==NULL ) return NULL; |
447 | |
448 if( http_hdr->method==NULL ) http_set_method( http_hdr, "GET"); | |
449 if( http_hdr->uri==NULL ) http_set_uri( http_hdr, "/"); | |
3497 | 450 else { |
18879 | 451 uri = malloc(strlen(http_hdr->uri) + 1); |
3497 | 452 if( uri==NULL ) { |
5915 | 453 mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); |
3497 | 454 return NULL; |
455 } | |
12391 | 456 strcpy(uri,http_hdr->uri); |
3497 | 457 } |
870 | 458 |
3497 | 459 //**** Compute the request length |
460 // Add the Method line | |
461 len = strlen(http_hdr->method)+strlen(uri)+12; | |
462 // Add the fields | |
463 field = http_hdr->first_field; | |
3039 | 464 while( field!=NULL ) { |
465 len += strlen(field->field_name)+2; | |
466 field = field->next; | |
467 } | |
3497 | 468 // Add the CRLF |
469 len += 2; | |
470 // Add the body | |
902 | 471 if( http_hdr->body!=NULL ) { |
472 len += http_hdr->body_size; | |
473 } | |
3497 | 474 // Free the buffer if it was previously used |
902 | 475 if( http_hdr->buffer!=NULL ) { |
476 free( http_hdr->buffer ); | |
477 http_hdr->buffer = NULL; | |
478 } | |
18879 | 479 http_hdr->buffer = malloc(len+1); |
902 | 480 if( http_hdr->buffer==NULL ) { |
5915 | 481 mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); |
902 | 482 return NULL; |
483 } | |
484 http_hdr->buffer_size = len; | |
485 | |
3497 | 486 //*** Building the request |
902 | 487 ptr = http_hdr->buffer; |
3497 | 488 // Add the method line |
489 ptr += sprintf( ptr, "%s %s HTTP/1.%d\r\n", http_hdr->method, uri, http_hdr->http_minor_version ); | |
3039 | 490 field = http_hdr->first_field; |
3497 | 491 // Add the field |
3039 | 492 while( field!=NULL ) { |
493 ptr += sprintf( ptr, "%s\r\n", field->field_name ); | |
494 field = field->next; | |
495 } | |
870 | 496 ptr += sprintf( ptr, "\r\n" ); |
3497 | 497 // Add the body |
870 | 498 if( http_hdr->body!=NULL ) { |
499 memcpy( ptr, http_hdr->body, http_hdr->body_size ); | |
500 } | |
3497 | 501 |
502 if( uri ) free( uri ); | |
902 | 503 return http_hdr->buffer; |
870 | 504 } |
505 | |
506 char * | |
507 http_get_field( HTTP_header_t *http_hdr, const char *field_name ) { | |
508 if( http_hdr==NULL || field_name==NULL ) return NULL; | |
3039 | 509 http_hdr->field_search_pos = http_hdr->first_field; |
510 http_hdr->field_search = (char*)realloc( http_hdr->field_search, strlen(field_name)+1 ); | |
870 | 511 if( http_hdr->field_search==NULL ) { |
5915 | 512 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
870 | 513 return NULL; |
514 } | |
515 strcpy( http_hdr->field_search, field_name ); | |
516 return http_get_next_field( http_hdr ); | |
517 } | |
518 | |
519 char * | |
520 http_get_next_field( HTTP_header_t *http_hdr ) { | |
521 char *ptr; | |
3039 | 522 HTTP_field_t *field; |
870 | 523 if( http_hdr==NULL ) return NULL; |
524 | |
3039 | 525 field = http_hdr->field_search_pos; |
526 while( field!=NULL ) { | |
527 ptr = strstr( field->field_name, ":" ); | |
870 | 528 if( ptr==NULL ) return NULL; |
3039 | 529 if( !strncasecmp( field->field_name, http_hdr->field_search, ptr-(field->field_name) ) ) { |
870 | 530 ptr++; // Skip the column |
531 while( ptr[0]==' ' ) ptr++; // Skip the spaces if there is some | |
3039 | 532 http_hdr->field_search_pos = field->next; |
870 | 533 return ptr; // return the value without the field name |
534 } | |
3039 | 535 field = field->next; |
870 | 536 } |
537 return NULL; | |
538 } | |
539 | |
540 void | |
3039 | 541 http_set_field( HTTP_header_t *http_hdr, const char *field_name ) { |
542 HTTP_field_t *new_field; | |
543 if( http_hdr==NULL || field_name==NULL ) return; | |
870 | 544 |
18879 | 545 new_field = malloc(sizeof(HTTP_field_t)); |
3039 | 546 if( new_field==NULL ) { |
5915 | 547 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
870 | 548 return; |
549 } | |
3039 | 550 new_field->next = NULL; |
18879 | 551 new_field->field_name = malloc(strlen(field_name)+1); |
3039 | 552 if( new_field->field_name==NULL ) { |
5915 | 553 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
3039 | 554 return; |
555 } | |
556 strcpy( new_field->field_name, field_name ); | |
557 | |
558 if( http_hdr->last_field==NULL ) { | |
559 http_hdr->first_field = new_field; | |
560 } else { | |
561 http_hdr->last_field->next = new_field; | |
562 } | |
563 http_hdr->last_field = new_field; | |
870 | 564 http_hdr->field_nb++; |
565 } | |
566 | |
567 void | |
568 http_set_method( HTTP_header_t *http_hdr, const char *method ) { | |
569 if( http_hdr==NULL || method==NULL ) return; | |
570 | |
18879 | 571 http_hdr->method = malloc(strlen(method)+1); |
870 | 572 if( http_hdr->method==NULL ) { |
5915 | 573 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
870 | 574 return; |
575 } | |
576 strcpy( http_hdr->method, method ); | |
577 } | |
578 | |
579 void | |
580 http_set_uri( HTTP_header_t *http_hdr, const char *uri ) { | |
581 if( http_hdr==NULL || uri==NULL ) return; | |
582 | |
18879 | 583 http_hdr->uri = malloc(strlen(uri)+1); |
870 | 584 if( http_hdr->uri==NULL ) { |
5915 | 585 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
870 | 586 return; |
587 } | |
588 strcpy( http_hdr->uri, uri ); | |
589 } | |
590 | |
6514 | 591 int |
592 http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ) { | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
593 char *auth = NULL, *usr_pass = NULL, *b64_usr_pass = NULL; |
6514 | 594 int encoded_len, pass_len=0, out_len; |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
595 int res = -1; |
6514 | 596 if( http_hdr==NULL || username==NULL ) return -1; |
597 | |
598 if( password!=NULL ) { | |
599 pass_len = strlen(password); | |
600 } | |
601 | |
18879 | 602 usr_pass = malloc(strlen(username)+pass_len+2); |
6514 | 603 if( usr_pass==NULL ) { |
604 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
605 goto out; |
6514 | 606 } |
607 | |
608 sprintf( usr_pass, "%s:%s", username, (password==NULL)?"":password ); | |
609 | |
610 // Base 64 encode with at least 33% more data than the original size | |
611 encoded_len = strlen(usr_pass)*2; | |
18879 | 612 b64_usr_pass = malloc(encoded_len); |
6514 | 613 if( b64_usr_pass==NULL ) { |
614 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
615 goto out; |
6514 | 616 } |
617 | |
618 out_len = base64_encode( usr_pass, strlen(usr_pass), b64_usr_pass, encoded_len); | |
619 if( out_len<0 ) { | |
620 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Base64 out overflow\n"); | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
621 goto out; |
6514 | 622 } |
623 | |
624 b64_usr_pass[out_len]='\0'; | |
625 | |
18879 | 626 auth = malloc(encoded_len+22); |
6514 | 627 if( auth==NULL ) { |
628 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
629 goto out; |
6514 | 630 } |
631 | |
632 sprintf( auth, "Authorization: Basic %s", b64_usr_pass); | |
633 http_set_field( http_hdr, auth ); | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
634 res = 0; |
6514 | 635 |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
636 out: |
6514 | 637 free( usr_pass ); |
638 free( b64_usr_pass ); | |
639 free( auth ); | |
640 | |
18094
16f2bcd5d148
free memory on error in http_add_basic_authentication
reimar
parents:
17932
diff
changeset
|
641 return res; |
6514 | 642 } |
643 | |
870 | 644 void |
645 http_debug_hdr( HTTP_header_t *http_hdr ) { | |
3039 | 646 HTTP_field_t *field; |
647 int i = 0; | |
902 | 648 if( http_hdr==NULL ) return; |
870 | 649 |
5915 | 650 mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- START ---\n"); |
651 mp_msg(MSGT_NETWORK,MSGL_V,"protocol: [%s]\n", http_hdr->protocol ); | |
652 mp_msg(MSGT_NETWORK,MSGL_V,"http minor version: [%d]\n", http_hdr->http_minor_version ); | |
653 mp_msg(MSGT_NETWORK,MSGL_V,"uri: [%s]\n", http_hdr->uri ); | |
654 mp_msg(MSGT_NETWORK,MSGL_V,"method: [%s]\n", http_hdr->method ); | |
655 mp_msg(MSGT_NETWORK,MSGL_V,"status code: [%d]\n", http_hdr->status_code ); | |
656 mp_msg(MSGT_NETWORK,MSGL_V,"reason phrase: [%s]\n", http_hdr->reason_phrase ); | |
657 mp_msg(MSGT_NETWORK,MSGL_V,"body size: [%d]\n", http_hdr->body_size ); | |
870 | 658 |
5915 | 659 mp_msg(MSGT_NETWORK,MSGL_V,"Fields:\n"); |
3039 | 660 field = http_hdr->first_field; |
661 while( field!=NULL ) { | |
5915 | 662 mp_msg(MSGT_NETWORK,MSGL_V," %d - %s\n", i++, field->field_name ); |
3039 | 663 field = field->next; |
664 } | |
5915 | 665 mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- END ---\n"); |
870 | 666 } |
6514 | 667 |
668 int | |
669 base64_encode(const void *enc, int encLen, char *out, int outMax) { | |
17778
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
670 static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
6514 | 671 |
672 unsigned char *encBuf; | |
673 int outLen; | |
674 unsigned int bits; | |
675 unsigned int shift; | |
676 | |
677 encBuf = (unsigned char*)enc; | |
678 outLen = 0; | |
679 bits = 0; | |
680 shift = 0; | |
17778
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
681 outMax &= ~3; |
6514 | 682 |
22031 | 683 while(1) { |
6514 | 684 if( encLen>0 ) { |
685 // Shift in byte | |
686 bits <<= 8; | |
687 bits |= *encBuf; | |
688 shift += 8; | |
689 // Next byte | |
690 encBuf++; | |
691 encLen--; | |
692 } else if( shift>0 ) { | |
693 // Pad last bits to 6 bits - will end next loop | |
694 bits <<= 6 - shift; | |
695 shift = 6; | |
696 } else { | |
17778
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
697 // As per RFC 2045, section 6.8, |
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
698 // pad output as necessary: 0 to 2 '=' chars. |
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
699 while( outLen & 3 ){ |
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
700 *out++ = '='; |
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
701 outLen++; |
37bfcf89c89c
Fix base64 encoding for basic auth according to RFC.
reimar
parents:
17566
diff
changeset
|
702 } |
6514 | 703 |
704 return outLen; | |
705 } | |
706 | |
707 // Encode 6 bit segments | |
708 while( shift>=6 ) { | |
22031 | 709 if (outLen >= outMax) |
710 return -1; | |
6514 | 711 shift -= 6; |
712 *out = b64[ (bits >> shift) & 0x3F ]; | |
713 out++; | |
714 outLen++; | |
715 } | |
716 } | |
717 } | |
718 | |
21567 | 719 //! If this function succeeds you must closesocket stream->fd |
15585 | 720 static int http_streaming_start(stream_t *stream, int* file_format) { |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
721 HTTP_header_t *http_hdr = NULL; |
15585 | 722 unsigned int i; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
723 int fd = stream->fd; |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
724 int res = STREAM_UNSUPPORTED; |
15585 | 725 int redirect = 0; |
726 int auth_retry=0; | |
727 int seekable=0; | |
728 char *content_type; | |
729 char *next_url; | |
730 URL_t *url = stream->streaming_ctrl->url; | |
6514 | 731 |
15585 | 732 do |
733 { | |
21541
3b4ed8857b38
Fix potential endless loop in http_streaming_start due
reimar
parents:
21540
diff
changeset
|
734 redirect = 0; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
735 if (fd > 0) closesocket(fd); |
15585 | 736 fd = http_send_request( url, 0 ); |
737 if( fd<0 ) { | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
738 goto err_out; |
15585 | 739 } |
740 | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
741 http_free(http_hdr); |
15585 | 742 http_hdr = http_read_response( fd ); |
743 if( http_hdr==NULL ) { | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
744 goto err_out; |
15585 | 745 } |
746 | |
17932 | 747 if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { |
15585 | 748 http_debug_hdr( http_hdr ); |
749 } | |
750 | |
751 // Check if we can make partial content requests and thus seek in http-streams | |
752 if( http_hdr!=NULL && http_hdr->status_code==200 ) { | |
753 char *accept_ranges; | |
754 if( (accept_ranges = http_get_field(http_hdr,"Accept-Ranges")) != NULL ) | |
755 seekable = strncmp(accept_ranges,"bytes",5)==0; | |
756 } | |
757 | |
758 // Check if the response is an ICY status_code reason_phrase | |
759 if( !strcasecmp(http_hdr->protocol, "ICY") ) { | |
760 switch( http_hdr->status_code ) { | |
761 case 200: { // OK | |
762 char *field_data = NULL; | |
763 // note: I skip icy-notice1 and 2, as they contain html <BR> | |
764 // and are IMHO useless info ::atmos | |
765 if( (field_data = http_get_field(http_hdr, "icy-name")) != NULL ) | |
766 mp_msg(MSGT_NETWORK,MSGL_INFO,"Name : %s\n", field_data); field_data = NULL; | |
767 if( (field_data = http_get_field(http_hdr, "icy-genre")) != NULL ) | |
768 mp_msg(MSGT_NETWORK,MSGL_INFO,"Genre : %s\n", field_data); field_data = NULL; | |
769 if( (field_data = http_get_field(http_hdr, "icy-url")) != NULL ) | |
770 mp_msg(MSGT_NETWORK,MSGL_INFO,"Website: %s\n", field_data); field_data = NULL; | |
771 // XXX: does this really mean public server? ::atmos | |
772 if( (field_data = http_get_field(http_hdr, "icy-pub")) != NULL ) | |
773 mp_msg(MSGT_NETWORK,MSGL_INFO,"Public : %s\n", atoi(field_data)?"yes":"no"); field_data = NULL; | |
774 if( (field_data = http_get_field(http_hdr, "icy-br")) != NULL ) | |
775 mp_msg(MSGT_NETWORK,MSGL_INFO,"Bitrate: %skbit/s\n", field_data); field_data = NULL; | |
776 | |
777 // If content-type == video/nsv we most likely have a winamp video stream | |
778 // otherwise it should be mp3. if there are more types consider adding mime type | |
779 // handling like later | |
780 if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "video/nsv") || !strcmp(field_data, "misc/ultravox"))) | |
781 *file_format = DEMUXER_TYPE_NSV; | |
16948
9b7925705f5b
Add another content-type for aac audio in shoutcast streams
rtognimp
parents:
16932
diff
changeset
|
782 else if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "audio/aacp") || !strcmp(field_data, "audio/aac"))) |
16917
c45409728a9d
Use correct demuxer type for aac in shoutcast streams
rtognimp
parents:
16614
diff
changeset
|
783 *file_format = DEMUXER_TYPE_AAC; |
15585 | 784 else |
785 *file_format = DEMUXER_TYPE_AUDIO; | |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
786 res = STREAM_ERROR; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
787 goto out; |
15585 | 788 } |
789 case 400: // Server Full | |
790 mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server is full, skipping!\n"); | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
791 goto err_out; |
15585 | 792 case 401: // Service Unavailable |
793 mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return service unavailable, skipping!\n"); | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
794 goto err_out; |
15585 | 795 case 403: // Service Forbidden |
796 mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return 'Service Forbidden'\n"); | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
797 goto err_out; |
15585 | 798 case 404: // Resource Not Found |
799 mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server couldn't find requested stream, skipping!\n"); | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
800 goto err_out; |
15585 | 801 default: |
802 mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: unhandled ICY-Errorcode, contact MPlayer developers!\n"); | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
803 goto err_out; |
15585 | 804 } |
805 } | |
806 | |
807 // Assume standard http if not ICY | |
808 switch( http_hdr->status_code ) { | |
809 case 200: // OK | |
810 // Look if we can use the Content-Type | |
811 content_type = http_get_field( http_hdr, "Content-Type" ); | |
812 if( content_type!=NULL ) { | |
813 char *content_length = NULL; | |
814 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type ); | |
815 if( (content_length = http_get_field(http_hdr, "Content-Length")) != NULL) | |
816 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length")); | |
817 // Check in the mime type table for a demuxer type | |
818 i = 0; | |
819 while(mime_type_table[i].mime_type != NULL) { | |
820 if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) { | |
821 *file_format = mime_type_table[i].demuxer_type; | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
822 res = seekable; |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
823 goto out; |
15585 | 824 } |
825 i++; | |
826 } | |
827 } | |
828 // Not found in the mime type table, don't fail, | |
829 // we should try raw HTTP | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
830 res = seekable; |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
831 goto out; |
15585 | 832 // Redirect |
833 case 301: // Permanently | |
834 case 302: // Temporarily | |
19459
6dad4b1efb82
Handle 303 (See Other) redirect, part of a patch by Benjamin Zores (ben at geexbox org)
reimar
parents:
19312
diff
changeset
|
835 case 303: // See Other |
15585 | 836 // TODO: RFC 2616, recommand to detect infinite redirection loops |
837 next_url = http_get_field( http_hdr, "Location" ); | |
838 if( next_url!=NULL ) { | |
25238
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
839 int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; |
20784
720206eef78b
Support URL redirections that do not specify full URL.
reimar
parents:
20185
diff
changeset
|
840 stream->streaming_ctrl->url = url_redirect( &url, next_url ); |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
841 if (!strcasecmp(url->protocol, "mms")) { |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
842 res = STREAM_REDIRECTED; |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
843 goto err_out; |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
844 } |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
845 if (strcasecmp(url->protocol, "http")) { |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
846 mp_msg(MSGT_NETWORK,MSGL_ERR,"Unsupported http %d redirect to %s protocol\n", http_hdr->status_code, url->protocol); |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
847 goto err_out; |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
848 } |
25238
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
849 if (is_ultravox) { |
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
850 free(url->protocol); |
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
851 url->protocol = strdup("unsv"); |
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
852 } |
15585 | 853 redirect = 1; |
854 } | |
855 break; | |
856 case 401: // Authentication required | |
21566
79d969f9eec0
STREAM_UNSUPPORTED is -1, so use the former for return value in all places.
reimar
parents:
21565
diff
changeset
|
857 if( http_authenticate(http_hdr, url, &auth_retry)<0 ) |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
858 goto err_out; |
15585 | 859 redirect = 1; |
860 break; | |
861 default: | |
862 mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
863 goto err_out; |
15585 | 864 } |
865 } while( redirect ); | |
866 | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
867 err_out: |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
868 if (fd > 0) closesocket( fd ); |
21565
546cf4a6377a
Make sure stream->fd is set correct (esp. to -1 on error when fd is closed)
reimar
parents:
21542
diff
changeset
|
869 fd = -1; |
21542 | 870 http_free( http_hdr ); |
21776 | 871 http_hdr = NULL; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
872 out: |
21776 | 873 stream->streaming_ctrl->data = (void*)http_hdr; |
21565
546cf4a6377a
Make sure stream->fd is set correct (esp. to -1 on error when fd is closed)
reimar
parents:
21542
diff
changeset
|
874 stream->fd = fd; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
875 return res; |
15585 | 876 } |
877 | |
878 static int fixup_open(stream_t *stream,int seekable) { | |
16013 | 879 HTTP_header_t *http_hdr = stream->streaming_ctrl->data; |
16078
095e980cf7c0
Some ICY servers (e.g. http://broadcast.spnet.net:8000/darikhigh) do not set
reimar
parents:
16070
diff
changeset
|
880 int is_icy = http_hdr && http_get_field(http_hdr, "Icy-MetaInt"); |
16070 | 881 int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; |
15585 | 882 |
883 stream->type = STREAMTYPE_STREAM; | |
16013 | 884 if(!is_icy && !is_ultravox && seekable) |
15585 | 885 { |
886 stream->flags |= STREAM_SEEK; | |
887 stream->seek = http_seek; | |
888 } | |
889 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
16013 | 890 if ((!is_icy && !is_ultravox) || scast_streaming_start(stream)) |
15585 | 891 if(nop_streaming_start( stream )) { |
892 mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n"); | |
21567 | 893 if (stream->fd >= 0) |
894 closesocket(stream->fd); | |
895 stream->fd = -1; | |
15585 | 896 streaming_ctrl_free(stream->streaming_ctrl); |
897 stream->streaming_ctrl = NULL; | |
24257 | 898 return STREAM_UNSUPPORTED; |
15585 | 899 } |
900 | |
901 fixup_network_stream_cache(stream); | |
902 return STREAM_OK; | |
903 } | |
904 | |
905 static int open_s1(stream_t *stream,int mode, void* opts, int* file_format) { | |
906 int seekable=0; | |
907 URL_t *url; | |
908 | |
909 stream->streaming_ctrl = streaming_ctrl_new(); | |
910 if( stream->streaming_ctrl==NULL ) { | |
911 return STREAM_ERROR; | |
912 } | |
913 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
914 url = url_new(stream->url); | |
915 stream->streaming_ctrl->url = check4proxies(url); | |
16417 | 916 url_free(url); |
15585 | 917 |
20185 | 918 mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(1), URL: %s\n", stream->url); |
15585 | 919 seekable = http_streaming_start(stream, file_format); |
920 if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) { | |
21567 | 921 if (stream->fd >= 0) |
922 closesocket(stream->fd); | |
923 stream->fd = -1; | |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
924 if (seekable == STREAM_REDIRECTED) |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
925 return seekable; |
15585 | 926 streaming_ctrl_free(stream->streaming_ctrl); |
927 stream->streaming_ctrl = NULL; | |
24257 | 928 return STREAM_UNSUPPORTED; |
15585 | 929 } |
930 | |
931 return fixup_open(stream, seekable); | |
932 } | |
933 | |
934 static int open_s2(stream_t *stream,int mode, void* opts, int* file_format) { | |
935 int seekable=0; | |
936 URL_t *url; | |
937 | |
938 stream->streaming_ctrl = streaming_ctrl_new(); | |
939 if( stream->streaming_ctrl==NULL ) { | |
940 return STREAM_ERROR; | |
941 } | |
942 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
943 url = url_new(stream->url); | |
944 stream->streaming_ctrl->url = check4proxies(url); | |
16614 | 945 url_free(url); |
15585 | 946 |
20185 | 947 mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(2), URL: %s\n", stream->url); |
15585 | 948 seekable = http_streaming_start(stream, file_format); |
949 if(seekable < 0) { | |
21567 | 950 if (stream->fd >= 0) |
951 closesocket(stream->fd); | |
952 stream->fd = -1; | |
15585 | 953 streaming_ctrl_free(stream->streaming_ctrl); |
954 stream->streaming_ctrl = NULL; | |
24257 | 955 return STREAM_UNSUPPORTED; |
15585 | 956 } |
957 | |
958 return fixup_open(stream, seekable); | |
959 } | |
960 | |
961 | |
25211 | 962 const stream_info_t stream_info_http1 = { |
15585 | 963 "http streaming", |
964 "null", | |
965 "Bertrand, Albeau, Reimar Doeffinger, Arpi?", | |
966 "plain http", | |
967 open_s1, | |
16013 | 968 {"http", "http_proxy", "unsv", NULL}, |
15585 | 969 NULL, |
970 0 // Urls are an option string | |
971 }; | |
972 | |
25211 | 973 const stream_info_t stream_info_http2 = { |
15585 | 974 "http streaming", |
975 "null", | |
976 "Bertrand, Albeu, Arpi? who?", | |
16932
c30e0970250c
fix typos: aslo->also, falback->fallback (they were just too annoying *g*)
reimar
parents:
16917
diff
changeset
|
977 "plain http, also used as fallback for many other protocols", |
15585 | 978 open_s2, |
979 {"http", "http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL}, //all the others as fallback | |
980 NULL, | |
981 0 // Urls are an option string | |
982 }; |