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