Mercurial > mplayer.hg
annotate stream/http.c @ 29328:c2ace2a6a01c
Enable fontconfig support by default. This change takes only in effect,
if fontconfig support is actually compiled in. If freetype is not
enabled, this patch should have no effect as well.
The visible result of this patch is to avoid the warning about a missing
~/.mplayer/subfont.ttf when starting mplayer (or gmplayer) without
parameters, like done from the .desktop file.
author | siretart |
---|---|
date | Wed, 17 Jun 2009 09:16:19 +0000 |
parents | 0f1b5b68af32 |
children | 4f740437ed2b |
rev | line source |
---|---|
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
1 /* |
902 | 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 |
28402 | 14 #if !HAVE_WINSOCK2_H |
27472
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
15 #else |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
16 #include <winsock2.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
17 #include <ws2tcpip.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
18 #endif |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
19 |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
20 #include "http.h" |
4816
f1dea39a50bb
Fixed the http response parser when the http header only has the HTTP
bertrand
parents:
4311
diff
changeset
|
21 #include "url.h" |
5915 | 22 #include "mp_msg.h" |
870 | 23 |
15585 | 24 #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
|
25 #include "libmpdemux/demuxer.h" |
15585 | 26 #include "network.h" |
27 #include "help_mp.h" | |
28 | |
29 | |
25246 | 30 extern const mime_struct_t mime_type_table[]; |
15585 | 31 extern int stream_cache_size; |
32 extern int network_bandwidth; | |
33 | |
28051 | 34 int http_seek(stream_t *stream, off_t pos); |
15585 | 35 |
16013 | 36 typedef struct { |
37 unsigned metaint; | |
38 unsigned metapos; | |
39 int is_ultravox; | |
40 } scast_data_t; | |
41 | |
42 /** | |
43 * \brief first read any data from sc->buffer then from fd | |
44 * \param fd file descriptor to read data from | |
45 * \param buffer buffer to read into | |
46 * \param len how many bytes to read | |
47 * \param sc streaming control containing buffer to read from first | |
48 * \return len unless there is a read error or eof | |
49 */ | |
50 static unsigned my_read(int fd, char *buffer, int len, streaming_ctrl_t *sc) { | |
51 unsigned pos = 0; | |
52 unsigned cp_len = sc->buffer_size - sc->buffer_pos; | |
53 if (cp_len > len) | |
54 cp_len = len; | |
55 memcpy(buffer, &sc->buffer[sc->buffer_pos], cp_len); | |
56 sc->buffer_pos += cp_len; | |
57 pos += cp_len; | |
58 while (pos < len) { | |
16070 | 59 int ret = recv(fd, &buffer[pos], len - pos, 0); |
16013 | 60 if (ret <= 0) |
61 break; | |
62 pos += ret; | |
63 } | |
64 return pos; | |
65 } | |
66 | |
16032 | 67 /** |
68 * \brief read and process (i.e. discard *g*) a block of ultravox metadata | |
69 * \param fd file descriptor to read from | |
70 * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd | |
71 * \return number of real data before next metadata block starts or 0 on error | |
72 */ | |
16013 | 73 static unsigned uvox_meta_read(int fd, streaming_ctrl_t *sc) { |
74 unsigned metaint; | |
16070 | 75 unsigned char info[6] = {0, 0, 0, 0, 0, 0}; |
76 int info_read; | |
16013 | 77 do { |
16070 | 78 info_read = my_read(fd, info, 1, sc); |
16013 | 79 if (info[0] == 0x00) |
16070 | 80 info_read = my_read(fd, info, 6, sc); |
16013 | 81 else |
16070 | 82 info_read += my_read(fd, &info[1], 5, sc); |
83 if (info_read != 6) // read error or eof | |
84 return 0; | |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
85 // sync byte and reserved flags |
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
86 if (info[0] != 0x5a || (info[1] & 0xfc) != 0x00) { |
16013 | 87 mp_msg(MSGT_DEMUXER, MSGL_ERR, "Invalid or unknown uvox metadata\n"); |
88 return 0; | |
89 } | |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
90 if (info[1] & 0x01) |
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
91 mp_msg(MSGT_DEMUXER, MSGL_WARN, "Encrypted ultravox data\n"); |
16013 | 92 metaint = info[4] << 8 | info[5]; |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
93 if ((info[3] & 0xf) < 0x07) { // discard any metadata nonsense |
16013 | 94 char *metabuf = malloc(metaint); |
95 my_read(fd, metabuf, metaint, sc); | |
96 free(metabuf); | |
97 } | |
16031
c2e78215f0d9
Ultravox improvements according to specs (didn't know they existed *g*)
reimar
parents:
16013
diff
changeset
|
98 } while ((info[3] & 0xf) < 0x07); |
16013 | 99 return metaint; |
100 } | |
101 | |
102 /** | |
103 * \brief read one scast meta data entry and print it | |
16032 | 104 * \param fd file descriptor to read from |
105 * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd | |
16013 | 106 */ |
107 static void scast_meta_read(int fd, streaming_ctrl_t *sc) { | |
108 unsigned char tmp = 0; | |
109 unsigned metalen; | |
110 my_read(fd, &tmp, 1, sc); | |
111 metalen = tmp * 16; | |
112 if (metalen > 0) { | |
18879 | 113 char *info = malloc(metalen + 1); |
16013 | 114 unsigned nlen = my_read(fd, info, metalen, sc); |
115 info[nlen] = 0; | |
116 mp_msg(MSGT_DEMUXER, MSGL_INFO, "\nICY Info: %s\n", info); | |
117 free(info); | |
118 } | |
119 } | |
120 | |
16032 | 121 /** |
122 * \brief read data from scast/ultravox stream without any metadata | |
123 * \param fd file descriptor to read from | |
124 * \param buffer buffer to read data into | |
125 * \param size number of bytes to read | |
126 * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd | |
127 */ | |
16013 | 128 static int scast_streaming_read(int fd, char *buffer, int size, |
129 streaming_ctrl_t *sc) { | |
130 scast_data_t *sd = (scast_data_t *)sc->data; | |
131 unsigned block, ret; | |
132 unsigned done = 0; | |
133 | |
134 // first read remaining data up to next metadata | |
135 block = sd->metaint - sd->metapos; | |
136 if (block > size) | |
137 block = size; | |
138 ret = my_read(fd, buffer, block, sc); | |
139 sd->metapos += ret; | |
140 done += ret; | |
141 if (ret != block) // read problems or eof | |
142 size = done; | |
143 | |
144 while (done < size) { // now comes the metadata | |
145 if (sd->is_ultravox) | |
16070 | 146 { |
16013 | 147 sd->metaint = uvox_meta_read(fd, sc); |
16070 | 148 if (!sd->metaint) |
149 size = done; | |
150 } | |
16013 | 151 else |
152 scast_meta_read(fd, sc); // read and display metadata | |
153 sd->metapos = 0; | |
154 block = size - done; | |
155 if (block > sd->metaint) | |
156 block = sd->metaint; | |
157 ret = my_read(fd, &buffer[done], block, sc); | |
158 sd->metapos += ret; | |
159 done += ret; | |
160 if (ret != block) // read problems or eof | |
161 size = done; | |
162 } | |
163 return done; | |
164 } | |
165 | |
166 static int scast_streaming_start(stream_t *stream) { | |
167 int metaint; | |
168 scast_data_t *scast_data; | |
169 HTTP_header_t *http_hdr = stream->streaming_ctrl->data; | |
16070 | 170 int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; |
16013 | 171 if (!stream || stream->fd < 0 || !http_hdr) |
172 return -1; | |
173 if (is_ultravox) | |
174 metaint = 0; | |
175 else { | |
176 metaint = atoi(http_get_field(http_hdr, "Icy-MetaInt")); | |
177 if (metaint <= 0) | |
178 return -1; | |
179 } | |
180 stream->streaming_ctrl->buffer = malloc(http_hdr->body_size); | |
181 stream->streaming_ctrl->buffer_size = http_hdr->body_size; | |
182 stream->streaming_ctrl->buffer_pos = 0; | |
183 memcpy(stream->streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size); | |
184 scast_data = malloc(sizeof(scast_data_t)); | |
185 scast_data->metaint = metaint; | |
186 scast_data->metapos = 0; | |
187 scast_data->is_ultravox = is_ultravox; | |
188 http_free(http_hdr); | |
189 stream->streaming_ctrl->data = scast_data; | |
190 stream->streaming_ctrl->streaming_read = scast_streaming_read; | |
191 stream->streaming_ctrl->streaming_seek = NULL; | |
192 stream->streaming_ctrl->prebuffer_size = 64 * 1024; // 64 KBytes | |
193 stream->streaming_ctrl->buffering = 1; | |
194 stream->streaming_ctrl->status = streaming_playing_e; | |
195 return 0; | |
196 } | |
197 | |
15585 | 198 static int nop_streaming_start( stream_t *stream ) { |
199 HTTP_header_t *http_hdr = NULL; | |
200 char *next_url=NULL; | |
201 URL_t *rd_url=NULL; | |
202 int fd,ret; | |
203 if( stream==NULL ) return -1; | |
204 | |
205 fd = stream->fd; | |
206 if( fd<0 ) { | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
207 fd = http_send_request( stream->streaming_ctrl->url, 0 ); |
15585 | 208 if( fd<0 ) return -1; |
209 http_hdr = http_read_response( fd ); | |
210 if( http_hdr==NULL ) return -1; | |
211 | |
212 switch( http_hdr->status_code ) { | |
213 case 200: // OK | |
214 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") ); | |
215 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") ); | |
216 if( http_hdr->body_size>0 ) { | |
217 if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { | |
218 http_free( http_hdr ); | |
219 return -1; | |
220 } | |
221 } | |
222 break; | |
223 // Redirect | |
224 case 301: // Permanently | |
225 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
|
226 case 303: // See Other |
15585 | 227 ret=-1; |
228 next_url = http_get_field( http_hdr, "Location" ); | |
229 | |
230 if (next_url != NULL) | |
231 rd_url=url_new(next_url); | |
232 | |
233 if (next_url != NULL && rd_url != NULL) { | |
234 mp_msg(MSGT_NETWORK,MSGL_STATUS,"Redirected: Using this url instead %s\n",next_url); | |
235 stream->streaming_ctrl->url=check4proxies(rd_url); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
236 ret=nop_streaming_start(stream); //recursively get streaming started |
15585 | 237 } else { |
238 mp_msg(MSGT_NETWORK,MSGL_ERR,"Redirection failed\n"); | |
239 closesocket( fd ); | |
240 fd = -1; | |
241 } | |
242 return ret; | |
243 break; | |
244 case 401: //Authorization required | |
245 case 403: //Forbidden | |
246 case 404: //Not found | |
247 case 500: //Server Error | |
248 default: | |
249 mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned code %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); | |
250 closesocket( fd ); | |
251 fd = -1; | |
252 return -1; | |
253 break; | |
254 } | |
255 stream->fd = fd; | |
256 } else { | |
257 http_hdr = (HTTP_header_t*)stream->streaming_ctrl->data; | |
258 if( http_hdr->body_size>0 ) { | |
259 if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { | |
260 http_free( http_hdr ); | |
261 stream->streaming_ctrl->data = NULL; | |
262 return -1; | |
263 } | |
264 } | |
265 } | |
266 | |
267 if( http_hdr ) { | |
268 http_free( http_hdr ); | |
269 stream->streaming_ctrl->data = NULL; | |
270 } | |
271 | |
272 stream->streaming_ctrl->streaming_read = nop_streaming_read; | |
273 stream->streaming_ctrl->streaming_seek = nop_streaming_seek; | |
274 stream->streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes | |
275 stream->streaming_ctrl->buffering = 1; | |
276 stream->streaming_ctrl->status = streaming_playing_e; | |
277 return 0; | |
278 } | |
279 | |
870 | 280 HTTP_header_t * |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
16948
diff
changeset
|
281 http_new_header(void) { |
870 | 282 HTTP_header_t *http_hdr; |
283 | |
18879 | 284 http_hdr = malloc(sizeof(HTTP_header_t)); |
870 | 285 if( http_hdr==NULL ) return NULL; |
286 memset( http_hdr, 0, sizeof(HTTP_header_t) ); | |
287 | |
288 return http_hdr; | |
289 } | |
290 | |
291 void | |
292 http_free( HTTP_header_t *http_hdr ) { | |
3039 | 293 HTTP_field_t *field, *field2free; |
870 | 294 if( http_hdr==NULL ) return; |
295 if( http_hdr->protocol!=NULL ) free( http_hdr->protocol ); | |
296 if( http_hdr->uri!=NULL ) free( http_hdr->uri ); | |
297 if( http_hdr->reason_phrase!=NULL ) free( http_hdr->reason_phrase ); | |
298 if( http_hdr->field_search!=NULL ) free( http_hdr->field_search ); | |
902 | 299 if( http_hdr->method!=NULL ) free( http_hdr->method ); |
300 if( http_hdr->buffer!=NULL ) free( http_hdr->buffer ); | |
3039 | 301 field = http_hdr->first_field; |
302 while( field!=NULL ) { | |
303 field2free = field; | |
14460 | 304 if (field->field_name) |
305 free(field->field_name); | |
3039 | 306 field = field->next; |
307 free( field2free ); | |
308 } | |
870 | 309 free( http_hdr ); |
3039 | 310 http_hdr = NULL; |
870 | 311 } |
312 | |
902 | 313 int |
314 http_response_append( HTTP_header_t *http_hdr, char *response, int length ) { | |
1027 | 315 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
|
316 |
18558
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
317 if( (unsigned)length > SIZE_MAX - http_hdr->buffer_size - 1) { |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
318 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
|
319 return -1; |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
320 } |
7293 | 321 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
|
322 if( http_hdr->buffer==NULL ) { |
7293 | 323 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory (re)allocation failed\n"); |
902 | 324 return -1; |
325 } | |
7293 | 326 memcpy( http_hdr->buffer+http_hdr->buffer_size, response, length ); |
327 http_hdr->buffer_size += length; | |
328 http_hdr->buffer[http_hdr->buffer_size]=0; // close the string! | |
902 | 329 return http_hdr->buffer_size; |
330 } | |
331 | |
332 int | |
2489
0ecc1b4f7cf8
Added ASF http server streaming (Not mms streaming).
bertrand
parents:
2310
diff
changeset
|
333 http_is_header_entire( HTTP_header_t *http_hdr ) { |
902 | 334 if( http_hdr==NULL ) return -1; |
7293 | 335 if( http_hdr->buffer==NULL ) return 0; // empty |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
336 |
3784 | 337 if( strstr(http_hdr->buffer, "\r\n\r\n")==NULL && |
338 strstr(http_hdr->buffer, "\n\n")==NULL ) return 0; | |
339 return 1; | |
902 | 340 } |
341 | |
342 int | |
343 http_response_parse( HTTP_header_t *http_hdr ) { | |
870 | 344 char *hdr_ptr, *ptr; |
345 char *field=NULL; | |
18558
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
346 int pos_hdr_sep, hdr_sep_len; |
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18094
diff
changeset
|
347 size_t len; |
902 | 348 if( http_hdr==NULL ) return -1; |
349 if( http_hdr->is_parsed ) return 0; | |
870 | 350 |
351 // Get the protocol | |
902 | 352 hdr_ptr = strstr( http_hdr->buffer, " " ); |
870 | 353 if( hdr_ptr==NULL ) { |
5915 | 354 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. No space separator found.\n"); |
902 | 355 return -1; |
870 | 356 } |
902 | 357 len = hdr_ptr-http_hdr->buffer; |
18879 | 358 http_hdr->protocol = malloc(len+1); |
870 | 359 if( http_hdr->protocol==NULL ) { |
5915 | 360 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
902 | 361 return -1; |
870 | 362 } |
902 | 363 strncpy( http_hdr->protocol, http_hdr->buffer, len ); |
364 http_hdr->protocol[len]='\0'; | |
870 | 365 if( !strncasecmp( http_hdr->protocol, "HTTP", 4) ) { |
366 if( sscanf( http_hdr->protocol+5,"1.%d", &(http_hdr->http_minor_version) )!=1 ) { | |
5915 | 367 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get HTTP minor version.\n"); |
902 | 368 return -1; |
870 | 369 } |
370 } | |
371 | |
372 // Get the status code | |
373 if( sscanf( ++hdr_ptr, "%d", &(http_hdr->status_code) )!=1 ) { | |
5915 | 374 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get status code.\n"); |
902 | 375 return -1; |
870 | 376 } |
377 hdr_ptr += 4; | |
378 | |
379 // Get the reason phrase | |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
380 ptr = strstr( hdr_ptr, "\n" ); |
870 | 381 if( hdr_ptr==NULL ) { |
5915 | 382 mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get the reason phrase.\n"); |
902 | 383 return -1; |
870 | 384 } |
385 len = ptr-hdr_ptr; | |
18879 | 386 http_hdr->reason_phrase = malloc(len+1); |
870 | 387 if( http_hdr->reason_phrase==NULL ) { |
5915 | 388 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
902 | 389 return -1; |
870 | 390 } |
391 strncpy( http_hdr->reason_phrase, hdr_ptr, len ); | |
4311 | 392 if( http_hdr->reason_phrase[len-1]=='\r' ) { |
393 len--; | |
394 } | |
870 | 395 http_hdr->reason_phrase[len]='\0'; |
396 | |
397 // 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
|
398 hdr_sep_len = 4; |
902 | 399 ptr = strstr( http_hdr->buffer, "\r\n\r\n" ); |
870 | 400 if( ptr==NULL ) { |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
401 ptr = strstr( http_hdr->buffer, "\n\n" ); |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
402 if( ptr==NULL ) { |
5915 | 403 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
|
404 return -1; |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
405 } |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
406 hdr_sep_len = 2; |
870 | 407 } |
902 | 408 pos_hdr_sep = ptr-http_hdr->buffer; |
870 | 409 |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
410 // 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
|
411 hdr_ptr = strstr( http_hdr->buffer, "\n" )+1; |
870 | 412 do { |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
413 ptr = hdr_ptr; |
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
414 while( *ptr!='\r' && *ptr!='\n' ) ptr++; |
870 | 415 len = ptr-hdr_ptr; |
4816
f1dea39a50bb
Fixed the http response parser when the http header only has the HTTP
bertrand
parents:
4311
diff
changeset
|
416 if( len==0 ) break; |
870 | 417 field = (char*)realloc(field, len+1); |
418 if( field==NULL ) { | |
5915 | 419 mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); |
902 | 420 return -1; |
870 | 421 } |
422 strncpy( field, hdr_ptr, len ); | |
423 field[len]='\0'; | |
424 http_set_field( http_hdr, field ); | |
3514
43518985def8
Handle broken server that doesn't send CRLF but jusr LF.
bertrand
parents:
3497
diff
changeset
|
425 hdr_ptr = ptr+((*ptr=='\r')?2:1); |
902 | 426 } while( hdr_ptr<(http_hdr->buffer+pos_hdr_sep) ); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
427 |
870 | 428 if( field!=NULL ) free( field ); |
429 | |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
430 if( pos_hdr_sep+hdr_sep_len<http_hdr->buffer_size ) { |
870 | 431 // Response has data! |
8179
63a5e03f4346
Removed hard coded value for the length of the header separator.
bertrand
parents:
7304
diff
changeset
|
432 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
|
433 http_hdr->body_size = http_hdr->buffer_size-(pos_hdr_sep+hdr_sep_len); |
870 | 434 } |
435 | |
902 | 436 http_hdr->is_parsed = 1; |
437 return 0; | |
870 | 438 } |
439 | |
440 char * | |
902 | 441 http_build_request( HTTP_header_t *http_hdr ) { |
3497 | 442 char *ptr, *uri=NULL; |
902 | 443 int len; |
3039 | 444 HTTP_field_t *field; |
870 | 445 if( http_hdr==NULL ) return NULL; |
446 | |
447 if( http_hdr->method==NULL ) http_set_method( http_hdr, "GET"); | |
448 if( http_hdr->uri==NULL ) http_set_uri( http_hdr, "/"); | |
3497 | 449 else { |
18879 | 450 uri = malloc(strlen(http_hdr->uri) + 1); |
3497 | 451 if( uri==NULL ) { |
5915 | 452 mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); |
3497 | 453 return NULL; |
454 } | |
12391 | 455 strcpy(uri,http_hdr->uri); |
3497 | 456 } |
870 | 457 |
3497 | 458 //**** Compute the request length |
459 // Add the Method line | |
460 len = strlen(http_hdr->method)+strlen(uri)+12; | |
461 // Add the fields | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
462 field = http_hdr->first_field; |
3039 | 463 while( field!=NULL ) { |
464 len += strlen(field->field_name)+2; | |
465 field = field->next; | |
466 } | |
3497 | 467 // Add the CRLF |
468 len += 2; | |
469 // Add the body | |
902 | 470 if( http_hdr->body!=NULL ) { |
471 len += http_hdr->body_size; | |
472 } | |
3497 | 473 // Free the buffer if it was previously used |
902 | 474 if( http_hdr->buffer!=NULL ) { |
475 free( http_hdr->buffer ); | |
476 http_hdr->buffer = NULL; | |
477 } | |
18879 | 478 http_hdr->buffer = malloc(len+1); |
902 | 479 if( http_hdr->buffer==NULL ) { |
5915 | 480 mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); |
902 | 481 return NULL; |
482 } | |
483 http_hdr->buffer_size = len; | |
484 | |
3497 | 485 //*** Building the request |
902 | 486 ptr = http_hdr->buffer; |
3497 | 487 // Add the method line |
488 ptr += sprintf( ptr, "%s %s HTTP/1.%d\r\n", http_hdr->method, uri, http_hdr->http_minor_version ); | |
3039 | 489 field = http_hdr->first_field; |
3497 | 490 // Add the field |
3039 | 491 while( field!=NULL ) { |
492 ptr += sprintf( ptr, "%s\r\n", field->field_name ); | |
493 field = field->next; | |
494 } | |
870 | 495 ptr += sprintf( ptr, "\r\n" ); |
3497 | 496 // Add the body |
870 | 497 if( http_hdr->body!=NULL ) { |
498 memcpy( ptr, http_hdr->body, http_hdr->body_size ); | |
499 } | |
3497 | 500 |
501 if( uri ) free( uri ); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
502 return http_hdr->buffer; |
870 | 503 } |
504 | |
505 char * | |
506 http_get_field( HTTP_header_t *http_hdr, const char *field_name ) { | |
507 if( http_hdr==NULL || field_name==NULL ) return NULL; | |
3039 | 508 http_hdr->field_search_pos = http_hdr->first_field; |
509 http_hdr->field_search = (char*)realloc( http_hdr->field_search, strlen(field_name)+1 ); | |
870 | 510 if( http_hdr->field_search==NULL ) { |
5915 | 511 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
870 | 512 return NULL; |
513 } | |
514 strcpy( http_hdr->field_search, field_name ); | |
515 return http_get_next_field( http_hdr ); | |
516 } | |
517 | |
518 char * | |
519 http_get_next_field( HTTP_header_t *http_hdr ) { | |
520 char *ptr; | |
3039 | 521 HTTP_field_t *field; |
870 | 522 if( http_hdr==NULL ) return NULL; |
523 | |
3039 | 524 field = http_hdr->field_search_pos; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
525 while( field!=NULL ) { |
3039 | 526 ptr = strstr( field->field_name, ":" ); |
870 | 527 if( ptr==NULL ) return NULL; |
3039 | 528 if( !strncasecmp( field->field_name, http_hdr->field_search, ptr-(field->field_name) ) ) { |
870 | 529 ptr++; // Skip the column |
530 while( ptr[0]==' ' ) ptr++; // Skip the spaces if there is some | |
3039 | 531 http_hdr->field_search_pos = field->next; |
870 | 532 return ptr; // return the value without the field name |
533 } | |
3039 | 534 field = field->next; |
870 | 535 } |
536 return NULL; | |
537 } | |
538 | |
539 void | |
3039 | 540 http_set_field( HTTP_header_t *http_hdr, const char *field_name ) { |
541 HTTP_field_t *new_field; | |
542 if( http_hdr==NULL || field_name==NULL ) return; | |
870 | 543 |
18879 | 544 new_field = malloc(sizeof(HTTP_field_t)); |
3039 | 545 if( new_field==NULL ) { |
5915 | 546 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
870 | 547 return; |
548 } | |
3039 | 549 new_field->next = NULL; |
18879 | 550 new_field->field_name = malloc(strlen(field_name)+1); |
3039 | 551 if( new_field->field_name==NULL ) { |
5915 | 552 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); |
27834
d35bcab9833b
Avoid a memleak if allocation of field_name fails, fixes bug #1319.
reimar
parents:
27473
diff
changeset
|
553 free(new_field); |
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 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
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'; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
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 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
631 |
6514 | 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; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
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 ); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
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 |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
668 int |
6514 | 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 | |
25970
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
719 static void print_icy_metadata(HTTP_header_t *http_hdr) { |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
720 const char *field_data; |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
721 // note: I skip icy-notice1 and 2, as they contain html <BR> |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
722 // and are IMHO useless info ::atmos |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
723 if( (field_data = http_get_field(http_hdr, "icy-name")) != NULL ) |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
724 mp_msg(MSGT_NETWORK,MSGL_INFO,"Name : %s\n", field_data); |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
725 if( (field_data = http_get_field(http_hdr, "icy-genre")) != NULL ) |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
726 mp_msg(MSGT_NETWORK,MSGL_INFO,"Genre : %s\n", field_data); |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
727 if( (field_data = http_get_field(http_hdr, "icy-url")) != NULL ) |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
728 mp_msg(MSGT_NETWORK,MSGL_INFO,"Website: %s\n", field_data); |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
729 // XXX: does this really mean public server? ::atmos |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
730 if( (field_data = http_get_field(http_hdr, "icy-pub")) != NULL ) |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
731 mp_msg(MSGT_NETWORK,MSGL_INFO,"Public : %s\n", atoi(field_data)?"yes":"no"); |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
732 if( (field_data = http_get_field(http_hdr, "icy-br")) != NULL ) |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
733 mp_msg(MSGT_NETWORK,MSGL_INFO,"Bitrate: %skbit/s\n", field_data); |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
734 } |
c6ec51cc3b13
Move printing of Icy-Metadata into an extra function
reimar
parents:
25969
diff
changeset
|
735 |
21567 | 736 //! If this function succeeds you must closesocket stream->fd |
15585 | 737 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
|
738 HTTP_header_t *http_hdr = NULL; |
15585 | 739 unsigned int i; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
740 int fd = stream->fd; |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
741 int res = STREAM_UNSUPPORTED; |
15585 | 742 int redirect = 0; |
743 int auth_retry=0; | |
744 int seekable=0; | |
745 char *content_type; | |
746 char *next_url; | |
747 URL_t *url = stream->streaming_ctrl->url; | |
6514 | 748 |
15585 | 749 do |
750 { | |
21541
3b4ed8857b38
Fix potential endless loop in http_streaming_start due
reimar
parents:
21540
diff
changeset
|
751 redirect = 0; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
752 if (fd > 0) closesocket(fd); |
15585 | 753 fd = http_send_request( url, 0 ); |
754 if( fd<0 ) { | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
755 goto err_out; |
15585 | 756 } |
757 | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
758 http_free(http_hdr); |
15585 | 759 http_hdr = http_read_response( fd ); |
760 if( http_hdr==NULL ) { | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
761 goto err_out; |
15585 | 762 } |
763 | |
17932 | 764 if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { |
15585 | 765 http_debug_hdr( http_hdr ); |
766 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
767 |
15585 | 768 // Check if we can make partial content requests and thus seek in http-streams |
769 if( http_hdr!=NULL && http_hdr->status_code==200 ) { | |
770 char *accept_ranges; | |
771 if( (accept_ranges = http_get_field(http_hdr,"Accept-Ranges")) != NULL ) | |
772 seekable = strncmp(accept_ranges,"bytes",5)==0; | |
773 } | |
774 | |
25971
64b1e4ea04fc
Always display Icy-Metadata if available, whether we recognize an ICY-Server
reimar
parents:
25970
diff
changeset
|
775 print_icy_metadata(http_hdr); |
64b1e4ea04fc
Always display Icy-Metadata if available, whether we recognize an ICY-Server
reimar
parents:
25970
diff
changeset
|
776 |
15585 | 777 // Check if the response is an ICY status_code reason_phrase |
25968
c7f41f9e2eb8
Detect IceCast also by Icy-MetaInt header part in http_streaming_start(),
reimar
parents:
25246
diff
changeset
|
778 if( !strcasecmp(http_hdr->protocol, "ICY") || |
c7f41f9e2eb8
Detect IceCast also by Icy-MetaInt header part in http_streaming_start(),
reimar
parents:
25246
diff
changeset
|
779 http_get_field(http_hdr, "Icy-MetaInt") ) { |
15585 | 780 switch( http_hdr->status_code ) { |
781 case 200: { // OK | |
25969 | 782 char *field_data; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
783 // If content-type == video/nsv we most likely have a winamp video stream |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
784 // otherwise it should be mp3. if there are more types consider adding mime type |
15585 | 785 // handling like later |
786 if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "video/nsv") || !strcmp(field_data, "misc/ultravox"))) | |
787 *file_format = DEMUXER_TYPE_NSV; | |
16948
9b7925705f5b
Add another content-type for aac audio in shoutcast streams
rtognimp
parents:
16932
diff
changeset
|
788 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
|
789 *file_format = DEMUXER_TYPE_AAC; |
15585 | 790 else |
791 *file_format = DEMUXER_TYPE_AUDIO; | |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
792 res = STREAM_ERROR; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
793 goto out; |
15585 | 794 } |
795 case 400: // Server Full | |
796 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
|
797 goto err_out; |
15585 | 798 case 401: // Service Unavailable |
799 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
|
800 goto err_out; |
15585 | 801 case 403: // Service Forbidden |
802 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
|
803 goto err_out; |
15585 | 804 case 404: // Resource Not Found |
805 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
|
806 goto err_out; |
15585 | 807 default: |
808 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
|
809 goto err_out; |
15585 | 810 } |
811 } | |
812 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
813 // Assume standard http if not ICY |
15585 | 814 switch( http_hdr->status_code ) { |
815 case 200: // OK | |
816 // Look if we can use the Content-Type | |
817 content_type = http_get_field( http_hdr, "Content-Type" ); | |
818 if( content_type!=NULL ) { | |
819 char *content_length = NULL; | |
820 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type ); | |
25999
aff1f94af7ba
Fill stream->end_pos if possible, fixing lavf demuxers that need to seek.
albeu
parents:
25972
diff
changeset
|
821 if( (content_length = http_get_field(http_hdr, "Content-Length")) != NULL) { |
15585 | 822 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length")); |
25999
aff1f94af7ba
Fill stream->end_pos if possible, fixing lavf demuxers that need to seek.
albeu
parents:
25972
diff
changeset
|
823 stream->end_pos = atoi(content_length); |
aff1f94af7ba
Fill stream->end_pos if possible, fixing lavf demuxers that need to seek.
albeu
parents:
25972
diff
changeset
|
824 } |
15585 | 825 // Check in the mime type table for a demuxer type |
826 i = 0; | |
827 while(mime_type_table[i].mime_type != NULL) { | |
828 if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) { | |
829 *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
|
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 } |
833 i++; | |
834 } | |
835 } | |
836 // Not found in the mime type table, don't fail, | |
837 // 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
|
838 res = seekable; |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
839 goto out; |
15585 | 840 // Redirect |
841 case 301: // Permanently | |
842 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
|
843 case 303: // See Other |
15585 | 844 // TODO: RFC 2616, recommand to detect infinite redirection loops |
845 next_url = http_get_field( http_hdr, "Location" ); | |
846 if( next_url!=NULL ) { | |
25238
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
847 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
|
848 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
|
849 if (!strcasecmp(url->protocol, "mms")) { |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
850 res = STREAM_REDIRECTED; |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
851 goto err_out; |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
852 } |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
853 if (strcasecmp(url->protocol, "http")) { |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
854 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
|
855 goto err_out; |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
856 } |
25238
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
857 if (is_ultravox) { |
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
858 free(url->protocol); |
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
859 url->protocol = strdup("unsv"); |
f42b8e689416
Preserve unsv:// protocol specifier over http redirects.
reimar
parents:
25211
diff
changeset
|
860 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
861 redirect = 1; |
15585 | 862 } |
863 break; | |
864 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
|
865 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
|
866 goto err_out; |
15585 | 867 redirect = 1; |
868 break; | |
869 default: | |
870 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
|
871 goto err_out; |
15585 | 872 } |
873 } while( redirect ); | |
874 | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
875 err_out: |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
876 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
|
877 fd = -1; |
21542 | 878 http_free( http_hdr ); |
21776 | 879 http_hdr = NULL; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
880 out: |
21776 | 881 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
|
882 stream->fd = fd; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
883 return res; |
15585 | 884 } |
885 | |
886 static int fixup_open(stream_t *stream,int seekable) { | |
16013 | 887 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
|
888 int is_icy = http_hdr && http_get_field(http_hdr, "Icy-MetaInt"); |
16070 | 889 int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; |
15585 | 890 |
891 stream->type = STREAMTYPE_STREAM; | |
16013 | 892 if(!is_icy && !is_ultravox && seekable) |
15585 | 893 { |
894 stream->flags |= STREAM_SEEK; | |
895 stream->seek = http_seek; | |
896 } | |
897 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
16013 | 898 if ((!is_icy && !is_ultravox) || scast_streaming_start(stream)) |
15585 | 899 if(nop_streaming_start( stream )) { |
900 mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n"); | |
21567 | 901 if (stream->fd >= 0) |
902 closesocket(stream->fd); | |
903 stream->fd = -1; | |
15585 | 904 streaming_ctrl_free(stream->streaming_ctrl); |
905 stream->streaming_ctrl = NULL; | |
24257 | 906 return STREAM_UNSUPPORTED; |
15585 | 907 } |
908 | |
909 fixup_network_stream_cache(stream); | |
910 return STREAM_OK; | |
911 } | |
912 | |
913 static int open_s1(stream_t *stream,int mode, void* opts, int* file_format) { | |
914 int seekable=0; | |
915 URL_t *url; | |
916 | |
917 stream->streaming_ctrl = streaming_ctrl_new(); | |
918 if( stream->streaming_ctrl==NULL ) { | |
919 return STREAM_ERROR; | |
920 } | |
921 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
922 url = url_new(stream->url); | |
923 stream->streaming_ctrl->url = check4proxies(url); | |
16417 | 924 url_free(url); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
925 |
20185 | 926 mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(1), URL: %s\n", stream->url); |
15585 | 927 seekable = http_streaming_start(stream, file_format); |
928 if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) { | |
21567 | 929 if (stream->fd >= 0) |
930 closesocket(stream->fd); | |
931 stream->fd = -1; | |
25135
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
932 if (seekable == STREAM_REDIRECTED) |
66f628d13442
Support stream redirection from http to mms, fix bug #927.
ulion
parents:
24257
diff
changeset
|
933 return seekable; |
15585 | 934 streaming_ctrl_free(stream->streaming_ctrl); |
935 stream->streaming_ctrl = NULL; | |
24257 | 936 return STREAM_UNSUPPORTED; |
15585 | 937 } |
938 | |
939 return fixup_open(stream, seekable); | |
940 } | |
941 | |
942 static int open_s2(stream_t *stream,int mode, void* opts, int* file_format) { | |
943 int seekable=0; | |
944 URL_t *url; | |
945 | |
946 stream->streaming_ctrl = streaming_ctrl_new(); | |
947 if( stream->streaming_ctrl==NULL ) { | |
948 return STREAM_ERROR; | |
949 } | |
950 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
951 url = url_new(stream->url); | |
952 stream->streaming_ctrl->url = check4proxies(url); | |
16614 | 953 url_free(url); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28402
diff
changeset
|
954 |
20185 | 955 mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(2), URL: %s\n", stream->url); |
15585 | 956 seekable = http_streaming_start(stream, file_format); |
957 if(seekable < 0) { | |
21567 | 958 if (stream->fd >= 0) |
959 closesocket(stream->fd); | |
960 stream->fd = -1; | |
15585 | 961 streaming_ctrl_free(stream->streaming_ctrl); |
962 stream->streaming_ctrl = NULL; | |
24257 | 963 return STREAM_UNSUPPORTED; |
15585 | 964 } |
965 | |
966 return fixup_open(stream, seekable); | |
967 } | |
968 | |
969 | |
25211 | 970 const stream_info_t stream_info_http1 = { |
15585 | 971 "http streaming", |
972 "null", | |
973 "Bertrand, Albeau, Reimar Doeffinger, Arpi?", | |
974 "plain http", | |
975 open_s1, | |
27847
28deb37052cd
Add a noicyx:// protocol to allow easier testing for misconfigured servers.
reimar
parents:
27834
diff
changeset
|
976 {"http", "http_proxy", "unsv", "icyx", "noicyx", NULL}, |
15585 | 977 NULL, |
978 0 // Urls are an option string | |
979 }; | |
980 | |
25211 | 981 const stream_info_t stream_info_http2 = { |
15585 | 982 "http streaming", |
983 "null", | |
984 "Bertrand, Albeu, Arpi? who?", | |
16932
c30e0970250c
fix typos: aslo->also, falback->fallback (they were just too annoying *g*)
reimar
parents:
16917
diff
changeset
|
985 "plain http, also used as fallback for many other protocols", |
15585 | 986 open_s2, |
987 {"http", "http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL}, //all the others as fallback | |
988 NULL, | |
989 0 // Urls are an option string | |
990 }; |