Mercurial > mplayer.hg
annotate stream/http.c @ 24851:e36efda34616
Our enca code uses strdup() on the input encoding name, as we don't modify it we can use the original constant string.
Uses less memory, code is simpler and faster.
Fixes memory leak (noticed by ulion).
author | iive |
---|---|
date | Sun, 28 Oct 2007 14:26:05 +0000 |
parents | d261f5109660 |
children | 66f628d13442 |
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 | |
31 extern mime_struct_t mime_type_table[]; | |
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; |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
724 int res = 0; |
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; | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
786 goto out; |
15585 | 787 } |
788 case 400: // Server Full | |
789 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
|
790 goto err_out; |
15585 | 791 case 401: // Service Unavailable |
792 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
|
793 goto err_out; |
15585 | 794 case 403: // Service Forbidden |
795 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
|
796 goto err_out; |
15585 | 797 case 404: // Resource Not Found |
798 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
|
799 goto err_out; |
15585 | 800 default: |
801 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
|
802 goto err_out; |
15585 | 803 } |
804 } | |
805 | |
806 // Assume standard http if not ICY | |
807 switch( http_hdr->status_code ) { | |
808 case 200: // OK | |
809 // Look if we can use the Content-Type | |
810 content_type = http_get_field( http_hdr, "Content-Type" ); | |
811 if( content_type!=NULL ) { | |
812 char *content_length = NULL; | |
813 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type ); | |
814 if( (content_length = http_get_field(http_hdr, "Content-Length")) != NULL) | |
815 mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length")); | |
816 // Check in the mime type table for a demuxer type | |
817 i = 0; | |
818 while(mime_type_table[i].mime_type != NULL) { | |
819 if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) { | |
820 *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
|
821 res = seekable; |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
822 goto out; |
15585 | 823 } |
824 i++; | |
825 } | |
826 } | |
827 // Not found in the mime type table, don't fail, | |
828 // 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
|
829 res = seekable; |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
830 goto out; |
15585 | 831 // Redirect |
832 case 301: // Permanently | |
833 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
|
834 case 303: // See Other |
15585 | 835 // TODO: RFC 2616, recommand to detect infinite redirection loops |
836 next_url = http_get_field( http_hdr, "Location" ); | |
837 if( next_url!=NULL ) { | |
20784
720206eef78b
Support URL redirections that do not specify full URL.
reimar
parents:
20185
diff
changeset
|
838 stream->streaming_ctrl->url = url_redirect( &url, next_url ); |
15585 | 839 redirect = 1; |
840 } | |
841 break; | |
842 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
|
843 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
|
844 goto err_out; |
15585 | 845 redirect = 1; |
846 break; | |
847 default: | |
848 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
|
849 goto err_out; |
15585 | 850 } |
851 } while( redirect ); | |
852 | |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
853 err_out: |
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
854 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
|
855 fd = -1; |
24257 | 856 res = STREAM_UNSUPPORTED; |
21542 | 857 http_free( http_hdr ); |
21776 | 858 http_hdr = NULL; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
859 out: |
21776 | 860 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
|
861 stream->fd = fd; |
21540
147c1c305f21
Fix lots and lots of potential memory/fd leaks in http_streaming_start
reimar
parents:
20784
diff
changeset
|
862 return res; |
15585 | 863 } |
864 | |
865 static int fixup_open(stream_t *stream,int seekable) { | |
16013 | 866 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
|
867 int is_icy = http_hdr && http_get_field(http_hdr, "Icy-MetaInt"); |
16070 | 868 int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; |
15585 | 869 |
870 stream->type = STREAMTYPE_STREAM; | |
16013 | 871 if(!is_icy && !is_ultravox && seekable) |
15585 | 872 { |
873 stream->flags |= STREAM_SEEK; | |
874 stream->seek = http_seek; | |
875 } | |
876 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
16013 | 877 if ((!is_icy && !is_ultravox) || scast_streaming_start(stream)) |
15585 | 878 if(nop_streaming_start( stream )) { |
879 mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n"); | |
21567 | 880 if (stream->fd >= 0) |
881 closesocket(stream->fd); | |
882 stream->fd = -1; | |
15585 | 883 streaming_ctrl_free(stream->streaming_ctrl); |
884 stream->streaming_ctrl = NULL; | |
24257 | 885 return STREAM_UNSUPPORTED; |
15585 | 886 } |
887 | |
888 fixup_network_stream_cache(stream); | |
889 return STREAM_OK; | |
890 } | |
891 | |
892 static int open_s1(stream_t *stream,int mode, void* opts, int* file_format) { | |
893 int seekable=0; | |
894 URL_t *url; | |
895 | |
896 stream->streaming_ctrl = streaming_ctrl_new(); | |
897 if( stream->streaming_ctrl==NULL ) { | |
898 return STREAM_ERROR; | |
899 } | |
900 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
901 url = url_new(stream->url); | |
902 stream->streaming_ctrl->url = check4proxies(url); | |
16417 | 903 url_free(url); |
15585 | 904 |
20185 | 905 mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(1), URL: %s\n", stream->url); |
15585 | 906 seekable = http_streaming_start(stream, file_format); |
907 if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) { | |
21567 | 908 if (stream->fd >= 0) |
909 closesocket(stream->fd); | |
910 stream->fd = -1; | |
15585 | 911 streaming_ctrl_free(stream->streaming_ctrl); |
912 stream->streaming_ctrl = NULL; | |
24257 | 913 return STREAM_UNSUPPORTED; |
15585 | 914 } |
915 | |
916 return fixup_open(stream, seekable); | |
917 } | |
918 | |
919 static int open_s2(stream_t *stream,int mode, void* opts, int* file_format) { | |
920 int seekable=0; | |
921 URL_t *url; | |
922 | |
923 stream->streaming_ctrl = streaming_ctrl_new(); | |
924 if( stream->streaming_ctrl==NULL ) { | |
925 return STREAM_ERROR; | |
926 } | |
927 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
928 url = url_new(stream->url); | |
929 stream->streaming_ctrl->url = check4proxies(url); | |
16614 | 930 url_free(url); |
15585 | 931 |
20185 | 932 mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(2), URL: %s\n", stream->url); |
15585 | 933 seekable = http_streaming_start(stream, file_format); |
934 if(seekable < 0) { | |
21567 | 935 if (stream->fd >= 0) |
936 closesocket(stream->fd); | |
937 stream->fd = -1; | |
15585 | 938 streaming_ctrl_free(stream->streaming_ctrl); |
939 stream->streaming_ctrl = NULL; | |
24257 | 940 return STREAM_UNSUPPORTED; |
15585 | 941 } |
942 | |
943 return fixup_open(stream, seekable); | |
944 } | |
945 | |
946 | |
947 stream_info_t stream_info_http1 = { | |
948 "http streaming", | |
949 "null", | |
950 "Bertrand, Albeau, Reimar Doeffinger, Arpi?", | |
951 "plain http", | |
952 open_s1, | |
16013 | 953 {"http", "http_proxy", "unsv", NULL}, |
15585 | 954 NULL, |
955 0 // Urls are an option string | |
956 }; | |
957 | |
958 stream_info_t stream_info_http2 = { | |
959 "http streaming", | |
960 "null", | |
961 "Bertrand, Albeu, Arpi? who?", | |
16932
c30e0970250c
fix typos: aslo->also, falback->fallback (they were just too annoying *g*)
reimar
parents:
16917
diff
changeset
|
962 "plain http, also used as fallback for many other protocols", |
15585 | 963 open_s2, |
964 {"http", "http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL}, //all the others as fallback | |
965 NULL, | |
966 0 // Urls are an option string | |
967 }; |