Fix an uninitialized value in the http reader.
[opusfile.git] / src / http.c
1 #include "internal.h"
2 #include <ctype.h>
3 #include <errno.h>
4 #include <limits.h>
5 #include <string.h>
6
7 typedef struct OpusParsedURL   OpusParsedURL;
8 typedef struct OpusStringBuf   OpusStringBuf;
9 typedef struct OpusHTTPConn    OpusHTTPConn;
10 typedef struct OpusHTTPStream  OpusHTTPStream;
11
12 static char *op_string_range_dup(const char *_start,const char *_end){
13   size_t  len;
14   char   *ret;
15   OP_ASSERT(_start<=_end);
16   len=_end-_start;
17   ret=(char *)_ogg_malloc(sizeof(*ret)*(len+1));
18   memcpy(ret,_start,sizeof(*ret)*(len));
19   ret[len]='\0';
20   return ret;
21 }
22
23 static char *op_string_dup(const char *_s){
24   return op_string_range_dup(_s,_s+strlen(_s));
25 }
26
27 /*Is this an https URL?
28   For now we can simply check the last letter.*/
29 #define OP_URL_IS_SSL(_url) ((_url)->scheme[4]=='s')
30
31 #define OP_URL_IS_DEFAULT_PORT(_url) \
32  (!OP_URL_IS_SSL(_url)&&(_url)->port==80 \
33  ||OP_URL_IS_SSL(_url)&&(_url)->port==443)
34
35 /*URI character classes (from RFC 3986).*/
36 #define OP_URL_ALPHA \
37  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
38 #define OP_URL_DIGIT       "01234567890"
39 #define OP_URL_HEXDIGIT    "01234567890ABCDEFabcdef"
40 /*Not a character class, but the characters allowed in <scheme>.*/
41 #define OP_URL_SCHEME      OP_URL_ALPHA OP_URL_DIGIT "+-."
42 #define OP_URL_GEN_DELIMS  "#/:?@[]"
43 #define OP_URL_SUB_DELIMS  "!$&'()*+,;="
44 #define OP_URL_RESERVED    OP_URL_GEN_DELIMS OP_URL_SUB_DELIMS
45 #define OP_URL_UNRESERVED  OP_URL_ALPHA OP_URL_DIGIT "-._~"
46 /*Not a character class, but the characters allowed in <pct-encoded>.*/
47 #define OP_URL_PCT_ENCODED "%"
48 /*Not a character class or production rule, but for convenience.*/
49 #define OP_URL_PCHAR_BASE \
50  OP_URL_UNRESERVED OP_URL_PCT_ENCODED OP_URL_SUB_DELIMS
51 #define OP_URL_PCHAR       OP_URL_PCHAR_BASE ":@"
52 /*Not a character class, but the characters allowed in <userinfo> and
53    <IP-literal>.*/
54 #define OP_URL_PCHAR_NA    OP_URL_PCHAR_BASE ":"
55 /*Not a character class, but the characters allowed in <segment-nz-nc>.*/
56 #define OP_URL_PCHAR_NC    OP_URL_PCHAR_BASE "@"
57 /*Not a character clsss, but the characters allowed in <path>.*/
58 #define OP_URL_PATH        OP_URL_PCHAR "/"
59 /*Not a character class, but the characters allowed in <query> / <fragment>.*/
60 #define OP_URL_QUERY_FRAG  OP_URL_PCHAR "/?"
61
62 /*Check the <% HEXDIG HEXDIG> escapes of a URL for validity.
63   Return: 0 if valid, or a negative value on failure.*/
64 static int op_validate_url_escapes(const char *_s){
65   int i;
66   for(i=0;_s[i];i++){
67     if(_s[i]=='%'){
68       if(OP_UNLIKELY(!isxdigit(_s[i+1]))
69        ||OP_UNLIKELY(!isxdigit(_s[i+2]))
70        /*RFC 3986 says %00 "should be rejected if the application is not
71           expecting to receive raw data within a component."*/
72        ||OP_UNLIKELY(_s[i+1]=='0'&&_s[i+2]=='0')){
73         return OP_FALSE;
74       }
75       i+=2;
76     }
77   }
78   return 0;
79 }
80
81 /*Convert a hex digit to its actual value.
82   _c: The hex digit to convert.
83       Presumed to be valid ('0'...'9', 'A'...'F', or 'a'...'f').
84   Return: The value of the digit, in the range [0,15].*/
85 static int op_hex_value(int _c){
86   return _c>='a'?_c-'a'+10:_c>='A'?_c-'A'+10:_c-'0';
87 }
88
89 /*Unescape all the <% HEXDIG HEXDIG> sequences in a string in-place.
90   This does no validity checking.*/
91 static char *op_unescape_url_component(char *_s){
92   int i;
93   int j;
94   for(i=j=0;_s[i];i++,j++){
95     if(_s[i]=='%'){
96       _s[i]=(char)(op_hex_value(_s[i+1])<<4|op_hex_value(_s[i+2]));
97       i+=2;
98     }
99   }
100   return _s;
101 }
102
103 /*Parse a file: URL.
104   This code is not meant to be fast: strspn() with large sets is likely to be
105    slow, but it is very convenient.
106   It is meant to be RFC 1738-compliant (as updated by RFC 3986).*/
107 static const char *op_parse_file_url(const char *_src){
108   const char *scheme_end;
109   const char *path;
110   const char *path_end;
111   scheme_end=_src+strspn(_src,OP_URL_SCHEME);
112   if(OP_UNLIKELY(*scheme_end!=':')
113    ||scheme_end-_src!=4||op_strncasecmp(_src,"file",4)!=0){
114     /*Unsupported protocol.*/
115     return NULL;
116   }
117   /*Make sure all escape sequences are valid to simplify unescaping later.*/
118   if(OP_UNLIKELY(op_validate_url_escapes(scheme_end+1)<0))return NULL;
119   if(scheme_end[1]=='/'&&scheme_end[2]=='/'){
120     const char *host;
121     const char *host_end;
122     char        host_buf[28];
123     /*file: URLs can have a host!
124       Yeah, I was surprised, too, but that's what RFC 1738 says.
125       It also says, "The file URL scheme is unusual in that it does not specify
126        an Internet protocol or access method for such files; as such, its
127        utility in network protocols between hosts is limited," which is a mild
128        understatement.*/
129     host=scheme_end+3;
130     /*The empty host is what we expect.*/
131     if(OP_LIKELY(*host!='/'))path=host;
132     /*RFC 1738 says localhost "is interpreted as `the machine from which the
133        URL is being interpreted,'" so let's check for it.*/
134     host_end=host+strspn(host,OP_URL_PCHAR_BASE);
135     /*No <port> allowed.
136       This also rejects IP-Literals.*/
137     if(*host_end!='/')return NULL;
138     /*An escaped "localhost" can take at most 27 characters.*/
139     if(OP_UNLIKELY(host_end-host>27))return NULL;
140     memcpy(host_buf,host,sizeof(*host_buf)*(host_end-host));
141     host_buf[host_end-host]='\0';
142     op_unescape_url_component(host_buf);
143     /*Some other host: give up.*/
144     if(OP_UNLIKELY(op_strncasecmp(host_buf,"localhost",9)!=0))return NULL;
145     path=host_end;
146   }
147   else path=scheme_end+1;
148   path_end=path+strspn(path,OP_URL_PATH);
149   /*This will reject a <query> or <fragment> component, too.
150     I don't know what to do with queries, but a temporal fragment would at
151      least make sense.
152     RFC 1738 pretty clearly defines a <searchpart> that's equivalent to the
153      RFC 3986 <query> component for other schemes, but not the file: scheme,
154      so I'm going to just reject it.*/
155   if(*path_end!='\0')return NULL;
156   return path;
157 }
158
159 #if defined(OP_ENABLE_HTTP)
160 # include <sys/types.h>
161 # include <sys/socket.h>
162 # include <sys/time.h>
163 # include <arpa/inet.h>
164 # include <fcntl.h>
165 # include <netinet/in.h>
166 # include <netdb.h>
167 # include <poll.h>
168 # include <unistd.h>
169 # include <openssl/ssl.h>
170
171 static char *op_string_tolower(char *_s){
172   int i;
173   for(i=0;_s[i]!='\0';i++){
174     int c;
175     c=_s[i];
176     if(c>='A'&&c<='Z')c+='a'-'A';
177     _s[i]=(char)c;
178   }
179   return _s;
180 }
181
182 struct OpusParsedURL{
183   /*Either "http" or "https".*/
184   char     *scheme;
185   /*The user name from the <userinfo> component, or NULL.*/
186   char     *user;
187   /*The password from the <userinfo> component, or NULL.*/
188   char     *pass;
189   /*The <host> component.
190     This may not be NULL.*/
191   char     *host;
192   /*The <path> and <query> components.
193     This may not be NULL.*/
194   char     *path;
195   /*The <port> component.
196     This is set to the default port if the URL did not contain one.*/
197   unsigned  port;
198 };
199
200 /*Parse a URL.
201   This code is not meant to be fast: strspn() with large sets is likely to be
202    slow, but it is very convenient.
203   It is meant to be RFC 3986-compliant.*/
204 static int op_parse_url_impl(OpusParsedURL *_dst,const char *_src){
205   const char  *scheme_end;
206   const char  *authority;
207   const char  *userinfo_end;
208   const char  *user;
209   const char  *user_end;
210   const char  *pass;
211   const char  *hostport;
212   const char  *hostport_end;
213   const char  *host_end;
214   const char  *port;
215   opus_int32   port_num;
216   const char  *port_end;
217   const char  *path;
218   const char  *path_end;
219   const char  *fragment_end;
220   const char  *uri_end;
221   scheme_end=_src+strspn(_src,OP_URL_SCHEME);
222   if(OP_UNLIKELY(*scheme_end!=':')
223    ||OP_UNLIKELY(scheme_end-_src<4)||OP_UNLIKELY(scheme_end-_src>5)
224    ||OP_UNLIKELY(op_strncasecmp(_src,"https",scheme_end-_src)!=0)){
225     /*Unsupported protocol.*/
226     return OP_EIMPL;
227   }
228   if(OP_UNLIKELY(scheme_end[1]!='/')||OP_UNLIKELY(scheme_end[2]!='/')){
229     /*We require an <authority> component.*/
230     return OP_EINVAL;
231   }
232   authority=scheme_end+3;
233   /*Make sure all escape sequences are valid to simplify unescaping later.*/
234   if(OP_UNLIKELY(op_validate_url_escapes(authority)<0))return OP_EINVAL;
235   /*Look for a <userinfo> component.*/
236   userinfo_end=authority+strspn(authority,OP_URL_PCHAR_NA);
237   if(*userinfo_end=='@'){
238     /*Found one.*/
239     user=authority;
240     /*Look for a password (yes, clear-text passwords are deprecated, I know,
241        but what else are people supposed to use? use SSL if you care).*/
242     user_end=authority+strspn(authority,OP_URL_PCHAR_BASE);
243     if(*user_end==':')pass=user_end+1;
244     else pass=NULL;
245     hostport=userinfo_end+1;
246   }
247   else{
248     user=NULL;
249     pass=NULL;
250     hostport=authority;
251   }
252   /*Try to figure out where the <host> component ends.*/
253   if(hostport[0]=='['){
254     hostport++;
255     /*We have an <IP-literal>, which can contain colons.*/
256     hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_NA);
257     if(OP_UNLIKELY(*hostport_end++!=']'))return OP_EINVAL;
258   }
259   /*Currently we don't support IDNA (RFC 5894), because I don't want to deal
260      with the policy about which domains should not be internationalized to
261      avoid confusing similarities.
262     Give this API Punycode (RFC 3492) domain names instead.*/
263   else hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_BASE);
264   /*TODO: Validate host.*/
265   /*Is there a port number?*/
266   port_num=-1;
267   if(*hostport_end==':'){
268     int i;
269     port=hostport_end+1;
270     port_end=port+strspn(port,OP_URL_DIGIT);
271     path=port_end;
272     /*Not part of RFC 3986, but require port numbers in the range 0...65535.*/
273     if(OP_LIKELY(port_end-port>0)){
274       while(*port=='0')port++;
275       if(OP_UNLIKELY(port_end-port>5))return OP_EINVAL;
276       port_num=0;
277       for(i=0;i<port_end-port;i++)port_num=port_num*10+port[i]-'0';
278       if(OP_UNLIKELY(port_num>65535))return OP_EINVAL;
279     }
280   }
281   else path=hostport_end;
282   path_end=path+strspn(path,OP_URL_PATH);
283   /*If the path is not empty, it must begin with a '/'.*/
284   if(OP_LIKELY(path_end>path)&&OP_UNLIKELY(path[0]!='/'))return OP_EINVAL;
285   /*Consume the <query> component, if any (right now we don't split this out
286      from the <path> component).*/
287   if(*path_end=='?')path_end=path_end+strspn(path_end,OP_URL_QUERY_FRAG);
288   /*Discard the <fragment> component, if any.
289     This doesn't get sent to the server.
290     Some day we should add support for Media Fragment URIs
291      <http://www.w3.org/TR/media-frags/>.*/
292   if(*path_end=='#'){
293     uri_end=fragment_end=path_end+1+strspn(path_end+1,OP_URL_QUERY_FRAG);
294   }
295   else uri_end=path_end;
296   /*If there's anything left, this was not a valid URL.*/
297   if(OP_UNLIKELY(*path_end!='\0'))return OP_EINVAL;
298   _dst->scheme=op_string_range_dup(_src,scheme_end);
299   if(OP_UNLIKELY(_dst->scheme==NULL))return OP_EFAULT;
300   op_string_tolower(_dst->scheme);
301   if(user!=NULL){
302     _dst->user=op_string_range_dup(user,user_end);
303     if(OP_UNLIKELY(_dst->user==NULL))return OP_EFAULT;
304     op_unescape_url_component(_dst->user);
305     /*Unescaping might have created a ':' in the username.
306       That's not allowed by RFC 2617's Basic Authentication Scheme.*/
307     if(OP_UNLIKELY(strchr(_dst->user,':')!=NULL))return OP_EINVAL;
308   }
309   else _dst->user=NULL;
310   if(pass!=NULL){
311     _dst->pass=op_string_range_dup(pass,userinfo_end);
312     if(OP_UNLIKELY(_dst->pass==NULL))return OP_EFAULT;
313     op_unescape_url_component(_dst->pass);
314   }
315   else _dst->pass=NULL;
316   _dst->host=op_string_range_dup(hostport,host_end);
317   if(OP_UNLIKELY(_dst->host==NULL))return OP_EFAULT;
318   if(port_num<0){
319     if(_src[4]=='s')port_num=443;
320     else port_num=80;
321   }
322   _dst->port=(unsigned)port_num;
323   /*RFC 2616 says an empty <abs-path> component is equivalent to "/", and we
324      MUST use the latter in the Request-URI.
325     Reserve space for the slash here.*/
326   if(path==path_end||path[0]=='?')path--;
327   _dst->path=op_string_range_dup(path,path_end);
328   if(OP_UNLIKELY(_dst->path==NULL))return OP_EFAULT;
329   /*And force-set it here.*/
330   _dst->path[0]='/';
331   return 0;
332 }
333
334 static void op_parsed_url_init(OpusParsedURL *_url){
335   memset(_url,0,sizeof(*_url));
336 }
337
338 static void op_parsed_url_clear(OpusParsedURL *_url){
339   _ogg_free(_url->scheme);
340   _ogg_free(_url->user);
341   _ogg_free(_url->pass);
342   _ogg_free(_url->host);
343   _ogg_free(_url->path);
344 }
345
346 static int op_parse_url(OpusParsedURL *_dst,const char *_src){
347   OpusParsedURL url;
348   int           ret;
349   op_parsed_url_init(&url);
350   ret=op_parse_url_impl(&url,_src);
351   if(OP_UNLIKELY(ret<0))op_parsed_url_clear(&url);
352   else *_dst=*&url;
353   return ret;
354 }
355
356 /*A buffer to hold growing strings.
357   The main purpose of this is to consolidate allocation checks and simplify
358    cleanup on a failed allocation.*/
359 struct OpusStringBuf{
360   char *buf;
361   int   nbuf;
362   int   cbuf;
363 };
364
365 static void op_sb_init(OpusStringBuf *_sb){
366   _sb->buf=NULL;
367   _sb->nbuf=0;
368   _sb->cbuf=0;
369 }
370
371 static void op_sb_clear(OpusStringBuf *_sb){
372   _ogg_free(_sb->buf);
373 }
374
375 static int op_sb_ensure_capacity(OpusStringBuf *_sb,int _capacity){
376   char *buf;
377   int   cbuf;
378   buf=_sb->buf;
379   cbuf=_sb->cbuf;
380   if(_capacity>=cbuf-1){
381     if(OP_UNLIKELY(cbuf>=INT_MAX-1>>1))return OP_EFAULT;
382     if(OP_UNLIKELY(_capacity>=INT_MAX-1))return OP_EFAULT;
383     cbuf=OP_MAX(2*cbuf+1,_capacity+1);
384     buf=_ogg_realloc(buf,sizeof(*buf)*cbuf);
385     if(OP_UNLIKELY(buf==NULL))return OP_EFAULT;
386     _sb->buf=buf;
387     _sb->cbuf=cbuf;
388   }
389   return 0;
390 }
391
392 static int op_sb_append(OpusStringBuf *_sb,const char *_s,int _len){
393   char *buf;
394   int   nbuf;
395   int   ret;
396   nbuf=_sb->nbuf;
397   if(OP_UNLIKELY(nbuf>INT_MAX-_len))return OP_EFAULT;
398   ret=op_sb_ensure_capacity(_sb,nbuf+_len);
399   if(OP_UNLIKELY(ret<0))return ret;
400   buf=_sb->buf;
401   memcpy(buf+nbuf,_s,sizeof(*buf)*_len);
402   nbuf+=_len;
403   buf[nbuf]='\0';
404   _sb->nbuf=nbuf;
405   return 0;
406 }
407
408 static int op_sb_append_string(OpusStringBuf *_sb,const char *_s){
409   return op_sb_append(_sb,_s,strlen(_s));
410 }
411
412 static int op_sb_append_nonnegative_int64(OpusStringBuf *_sb,opus_int64 _i){
413   char digit;
414   int  nbuf_start;
415   int  ret;
416   OP_ASSERT(_i>=0);
417   nbuf_start=_sb->nbuf;
418   ret=0;
419   do{
420     digit='0'+_i%10;
421     ret|=op_sb_append(_sb,&digit,1);
422     _i/=10;
423   }
424   while(_i>0);
425   if(OP_LIKELY(ret>=0)){
426     char *buf;
427     int   nbuf_end;
428     buf=_sb->buf;
429     nbuf_end=_sb->nbuf-1;
430     /*We've added the digits backwards.
431       Reverse them.*/
432     while(nbuf_start<nbuf_end){
433       digit=buf[nbuf_start];
434       buf[nbuf_start]=buf[nbuf_end];
435       buf[nbuf_end]=digit;
436       nbuf_start++;
437       nbuf_end--;
438     }
439   }
440   return ret;
441 }
442
443 struct OpusHTTPConn{
444   /*The current position indicator for this connection.*/
445   opus_int64    pos;
446   SSL          *ssl_conn;
447   OpusHTTPConn *next;
448   int           fd;
449 };
450
451 static void op_http_conn_init(OpusHTTPConn *_conn){
452   _conn->ssl_conn=NULL;
453   _conn->next=NULL;
454   _conn->fd=-1;
455 }
456
457 static void op_http_conn_clear(OpusHTTPConn *_conn){
458   if(_conn->ssl_conn!=NULL)SSL_free(_conn->ssl_conn);
459   /*SSL frees the BIO for us.*/
460   if(_conn->fd!=-1)close(_conn->fd);
461 }
462
463 /*The maximum number of simultaneous connections.
464   RFC 2616 says this SHOULD NOT be more than 2, but everyone on the modern web
465    ignores that.
466   If it makes you feel better, we'll only ever be reading from one of these at
467    a time; the others are kept around mainly to avoid slow-starting a new
468    connection if we seek back near somewhere we were reading before.*/
469 # define OP_NCONNS_MAX (4)
470
471 struct OpusHTTPStream{
472   /*The list of connections.*/
473   OpusHTTPConn     conns[OP_NCONNS_MAX];
474   /*The context object used as a framework for TLS/SSL functions.*/
475   SSL_CTX         *ssl_ctx;
476   /*The LRU list (ordered from MRU to LRU) of connections.*/
477   OpusHTTPConn    *lru_head;
478   /*The free list.*/
479   OpusHTTPConn    *free_head;
480   /*The URL to connect to.*/
481   OpusParsedURL    url;
482   /*The connection we're currently reading from.
483     This can be -1 if no connection is active.*/
484   int              cur_conni;
485   /*Information about the address we connected to.*/
486   struct addrinfo  addr_info;
487   /*The address we connected to.*/
488   union{
489     struct sockaddr     s;
490     struct sockaddr_in  v4;
491     struct sockaddr_in6 v6;
492   }                addr;
493   /*A buffer used to build HTTP requests.*/
494   OpusStringBuf    request;
495   /*The offset of the tail of the request.
496     Only the offset in the Range: header appears after this.*/
497   int              request_tail;
498   /*Whether or not the server supports range requests.*/
499   int              seekable;
500   /*The Content-Length, if specified, or -1 otherwise.
501     This will always be valid for seekable streams.*/
502   opus_int64       content_length;
503   /*The position indicator used when no connection is active.*/
504   opus_int64       pos;
505 };
506
507 static void op_http_stream_init(OpusHTTPStream *_stream){
508   OpusHTTPConn **pnext;
509   int ci;
510   pnext=&_stream->free_head;
511   for(ci=0;ci<OP_NCONNS_MAX;ci++){
512     op_http_conn_init(_stream->conns+ci);
513     *pnext=_stream->conns+ci;
514     pnext=&_stream->conns[ci].next;
515   }
516   _stream->ssl_ctx=NULL;
517   _stream->lru_head=NULL;
518   op_parsed_url_init(&_stream->url);
519   op_sb_init(&_stream->request);
520   _stream->seekable=0;
521 }
522
523 /*Close the connection at the top of the LRU list.*/
524 static void op_http_conn_close(OpusHTTPStream *_stream,OpusHTTPConn *_conn){
525   op_http_conn_clear(_conn);
526   _conn->ssl_conn=NULL;
527   _conn->fd=-1;
528   OP_ASSERT(_stream->lru_head==_conn);
529   _stream->lru_head=_conn->next;
530   _conn->next=_stream->free_head;
531   _stream->free_head=_conn;
532 }
533
534 static void op_http_stream_clear(OpusHTTPStream *_stream){
535   while(_stream->lru_head!=NULL)op_http_conn_close(_stream,_stream->lru_head);
536   if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx);
537   op_sb_clear(&_stream->request);
538   op_parsed_url_clear(&_stream->url);
539 }
540
541 static struct addrinfo *op_resolve(const char *_host,unsigned _port){
542   struct addrinfo *addrs;
543   struct addrinfo  hints;
544   char             service[6];
545   memset(&hints,0,sizeof(hints));
546   hints.ai_socktype=SOCK_STREAM;
547   OP_ASSERT(_port<=65535U);
548   sprintf(service,"%u",_port);
549   if(OP_LIKELY(!getaddrinfo(_host,service,&hints,&addrs)))return addrs;
550   return NULL;
551 }
552
553 static int op_sock_set_nonblocking(int _fd,int _nonblocking){
554   int flags;
555   flags=fcntl(_fd,F_GETFL);
556   if(OP_UNLIKELY(flags==-1))return flags;
557   if(_nonblocking)flags|=O_NONBLOCK;
558   else flags&=~O_NONBLOCK;
559   return fcntl(_fd,F_SETFL,flags);
560 }
561
562 /*Try to start a connection to the next address in the given list of a given
563    type.
564   _fd:         The socket to connect with.
565   [out] _addr: A pointer to the list of addresses.
566                This will be advanced to the first one that matches the given
567                 address family (possibly the current one).
568   _ai_family:  The address family to connect to.
569   Return: 1        If the connection was successful.
570           0        If the connection is in progress.
571           OP_FALSE If the connection failed and there were no more addresses
572                     left to try.
573                     *_addr will be set to NULL in this case.*/
574 static int op_sock_connect_next(int _fd,
575  struct addrinfo **_addr,int _ai_family){
576   struct addrinfo *addr;
577   addr=*_addr;
578   for(;;){
579     /*Move to the next address of the requested type.*/
580     for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next);
581     *_addr=addr;
582     /*No more: failure.*/
583     if(addr==NULL)return OP_FALSE;
584     if(connect(_fd,addr->ai_addr,addr->ai_addrlen)!=-1)return 1;
585     if(OP_LIKELY(errno==EINPROGRESS))return 0;
586   }
587 }
588
589 typedef int (*op_ssl_step_func)(SSL *_ssl_conn);
590
591 /*Try to run an SSL function to completion (blocking if necessary).*/
592 static int op_do_ssl_step(SSL *_ssl_conn,int _fd,op_ssl_step_func _step){
593   struct pollfd fd;
594   fd.fd=_fd;
595   for(;;){
596     int ret;
597     int err;
598     ret=(*_step)(_ssl_conn);
599     if(ret>=0)return ret;
600     err=SSL_get_error(_ssl_conn,ret);
601     if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
602     else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
603     else return OP_FALSE;
604     if(poll(&fd,1,-1)==-1)return OP_FALSE;
605   }
606 }
607
608 /*The number of address families to try connecting to simultaneously.*/
609 # define OP_NPROTOS (2)
610
611 static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
612  struct addrinfo *_addrs){
613   struct addrinfo *addr;
614   struct addrinfo *addrs[OP_NPROTOS];
615   struct pollfd    fds[OP_NPROTOS];
616   int              ai_family;
617   int              nprotos;
618   int              ret;
619   int              pi;
620   int              pj;
621   for(pi=0;pi<OP_NPROTOS;pi++)addrs[pi]=NULL;
622   addr=_addrs;
623   /*Try connecting via both IPv4 and IPv6 simultaneously, and keep the first
624      one that succeeds.*/
625   for(;addr!=NULL;addr=addr->ai_next){
626     /*Give IPv6 a slight edge by putting it first in the list.*/
627     if(addr->ai_family==AF_INET6){
628       OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in6));
629       if(addrs[0]==NULL)addrs[0]=addr;
630     }
631     else if(addr->ai_family==AF_INET){
632       OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in));
633       if(addrs[1]==NULL)addrs[1]=addr;
634     }
635   }
636   /*Consolidate the list of addresses.*/
637   for(pi=nprotos=0;pi<OP_NPROTOS;pi++){
638     if(addrs[pi]!=NULL){
639       addrs[nprotos]=addrs[pi];
640       nprotos++;
641     }
642   }
643   /*Try to start a connection to each protocol.*/
644   for(pi=0;pi<nprotos;pi++){
645     ai_family=addrs[pi]->ai_family;
646     fds[pi].fd=socket(ai_family,SOCK_STREAM,addrs[pi]->ai_protocol);
647     fds[pi].events=POLLOUT;
648     if(OP_LIKELY(fds[pi].fd!=-1)){
649       if(OP_LIKELY(op_sock_set_nonblocking(fds[pi].fd,1)!=-1)){
650         ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
651         if(ret>1){
652           /*It succeeded right away, so stop.*/
653           nprotos=pi+1;
654           break;
655         }
656         /*Otherwise go on to the next protocol, and skip the clean-up below.*/
657         else if(ret==0)continue;
658         /*Tried all the addresses for this protocol.*/
659       }
660       /*Clean up the socket.*/
661       close(fds[pi].fd);
662     }
663     /*Remove this protocol from the list.*/
664     memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
665     nprotos--;
666     pi--;
667   }
668   /*Wait for one of the connections to finish.*/
669   while(pi>=nprotos&&nprotos>0&&poll(fds,nprotos,-1)!=-1){
670     for(pi=0;pi<nprotos;pi++){
671       socklen_t errlen;
672       int       err;
673       /*Still waiting...*/
674       if(!fds[pi].revents)continue;
675       errlen=sizeof(err);
676       if(getsockopt(fds[pi].fd,SOL_SOCKET,SO_ERROR,&err,&errlen)!=-1&&err==0){
677         /*Success!*/
678         break;
679       }
680       /*Move on to the next address for this protocol.*/
681       ai_family=addrs[pi]->ai_family;
682       addrs[pi]=addrs[pi]->ai_next;
683       ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
684       /*It succeeded right away, so stop.*/
685       if(ret>0)break;
686       /*Otherwise go on to the next protocol, and skip the clean-up below.*/
687       else if(ret==0)continue;
688       /*Tried all the addresses for this protocol.
689         Remove it from the list.*/
690       close(fds[pi].fd);
691       memmove(fds+pi,fds+pi+1,sizeof(*fds)*(nprotos-pi-1));
692       memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
693       nprotos--;
694       pi--;
695     }
696   }
697   /*Close all the other sockets.*/
698   for(pj=0;pj<nprotos;pj++)if(pi!=pj)close(fds[pj].fd);
699   /*If none of them succeeded, we're done.*/
700   if(pi>=nprotos)return OP_FALSE;
701   /*Save this address for future connection attempts.*/
702   if(addrs[pi]!=&_stream->addr_info){
703     memcpy(&_stream->addr_info,addrs[pi],sizeof(_stream->addr_info));
704     _stream->addr_info.ai_addr=&_stream->addr.s;
705     _stream->addr_info.ai_next=NULL;
706     memcpy(&_stream->addr,addrs[pi]->ai_addr,addrs[pi]->ai_addrlen);
707   }
708   if(OP_URL_IS_SSL(&_stream->url)){
709     SSL *ssl_conn;
710     BIO *ssl_bio;
711     /*Start the SSL connection.*/
712     OP_ASSERT(_stream->ssl_ctx!=NULL);
713     ssl_conn=SSL_new(_stream->ssl_ctx);
714     if(OP_LIKELY(ssl_conn!=NULL)){
715       ssl_bio=BIO_new_socket(fds[pi].fd,BIO_NOCLOSE);
716       if(OP_LIKELY(ssl_bio!=NULL)){
717         SSL_set_bio(ssl_conn,ssl_bio,ssl_bio);
718         SSL_set_connect_state(ssl_conn);
719         ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_connect);
720         if(OP_LIKELY(ret>0)){
721           ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_do_handshake);
722           if(OP_LIKELY(ret>0)){
723             _conn->ssl_conn=ssl_conn;
724             _conn->fd=fds[pi].fd;
725             return 0;
726           }
727         }
728         /*If we wanted to shut down cleanly, we would do:
729         op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_shutdown);*/
730       }
731       SSL_free(ssl_conn);
732     }
733     close(fds[pi].fd);
734     return OP_FALSE;
735   }
736   /*Just a normal non-SSL connection.*/
737   _conn->ssl_conn=NULL;
738   _conn->fd=fds[pi].fd;
739   return 0;
740 }
741
742 # define OP_BASE64_LENGTH(_len) (((_len)+2)/3*4)
743
744 static const char BASE64_TABLE[64]={
745   'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
746   'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
747   'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
748   'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
749 };
750
751 static char *op_base64_encode(char *_dst,const char *_src,int _len){
752   unsigned s0;
753   unsigned s1;
754   unsigned s2;
755   int      ngroups;
756   int      i;
757   ngroups=_len/3;
758   for(i=0;i<ngroups;i++){
759     s0=_src[3*i+0];
760     s1=_src[3*i+1];
761     s2=_src[3*i+2];
762     _dst[4*i+0]=BASE64_TABLE[s0>>2];
763     _dst[4*i+1]=BASE64_TABLE[s0&3<<4|s1>>4];
764     _dst[4*i+2]=BASE64_TABLE[s1&15<<2|s2>>6];
765     _dst[4*i+3]=BASE64_TABLE[s2&63];
766   }
767   _len-=3*i;
768   if(_len==1){
769     s0=_src[3*i+0];
770     _dst[4*i+0]=BASE64_TABLE[s0>>2];
771     _dst[4*i+1]=BASE64_TABLE[s0&3<<4];
772     _dst[4*i+2]='=';
773     _dst[4*i+3]='=';
774     i++;
775   }
776   else if(_len==2){
777     s0=_src[3*i+0];
778     s1=_src[3*i+1];
779     _dst[4*i+0]=BASE64_TABLE[s0>>2];
780     _dst[4*i+1]=BASE64_TABLE[s0&3<<4|s1>>4];
781     _dst[4*i+2]=BASE64_TABLE[s1&15<<2];
782     _dst[4*i+3]='=';
783     i++;
784   }
785   _dst[4*i]='\0';
786   return _dst+4*i;
787 }
788
789 /*Construct an HTTP authorization header using RFC 2617's Basic Authentication
790    Scheme and append it to the given string buffer.*/
791 static int op_sb_append_basic_auth_header(OpusStringBuf *_sb,
792  const char *_header,const char *_user,const char *_pass){
793   int user_len;
794   int pass_len;
795   int user_pass_len;
796   int base64_len;
797   int nbuf_total;
798   int ret;
799   ret=op_sb_append_string(_sb,_header);
800   ret|=op_sb_append(_sb,": Basic ",8);
801   user_len=strlen(_user);
802   pass_len=strlen(_pass);
803   if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT;
804   if(OP_UNLIKELY(user_len+pass_len>(INT_MAX>>2)*3-3))return OP_EFAULT;
805   user_pass_len=user_len+1+pass_len;
806   base64_len=OP_BASE64_LENGTH(user_pass_len);
807   /*Stick "user:pass" at the end of the buffer so we can Base64 encode it
808      in-place.*/
809   nbuf_total=_sb->nbuf;
810   if(OP_UNLIKELY(base64_len>INT_MAX-nbuf_total))return OP_EFAULT;
811   nbuf_total+=base64_len;
812   ret|=op_sb_ensure_capacity(_sb,nbuf_total);
813   if(OP_UNLIKELY(ret<0))return ret;
814   _sb->nbuf=nbuf_total-user_pass_len;
815   ret=op_sb_append(_sb,_user,user_len);
816   OP_ASSERT(!ret);
817   ret=op_sb_append(_sb,":",1);
818   OP_ASSERT(!ret);
819   ret=op_sb_append(_sb,_pass,pass_len);
820   OP_ASSERT(!ret);
821   op_base64_encode(_sb->buf+nbuf_total-base64_len,
822    _sb->buf+nbuf_total-user_pass_len,user_pass_len);
823   return op_sb_append(_sb,"\r\n",2);
824 }
825
826 static int op_http_conn_write_fully(OpusHTTPConn *_conn,
827  const char *_buf,int _size){
828   struct pollfd  fd;
829   SSL           *ssl_conn;
830   fd.fd=_conn->fd;
831   ssl_conn=_conn->ssl_conn;
832   while(_size>0){
833     int err;
834     if(ssl_conn!=NULL){
835       int ret;
836       ret=SSL_write(ssl_conn,_buf,_size);
837       if(ret>0){
838         /*Wrote some data.*/
839         _buf+=ret;
840         _size-=ret;
841         continue;
842       }
843       /*Connection closed.*/
844       else if(ret==0)return OP_FALSE;
845       err=SSL_get_error(ssl_conn,ret);
846       /*Yes, renegotiations can cause SSL_write() to block for reading.*/
847       if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
848       else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
849       else return OP_FALSE;
850     }
851     else{
852       ssize_t ret;
853       errno=0;
854       ret=write(fd.fd,_buf,_size);
855       if(ret>0){
856         _buf+=ret;
857         _size-=ret;
858         continue;
859       }
860       err=errno;
861       if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_FALSE;
862       fd.events=POLLOUT;
863     }
864     if(poll(&fd,1,-1)==-1)return OP_FALSE;
865   }
866   return 0;
867 }
868
869 /*Tries to read from the given connection.
870   [out] _buf: Returns the data read.
871   _size:      The size of the buffer.
872   _block      Whether or not to block until some data is retrieved.*/
873 static ptrdiff_t op_http_conn_read(OpusHTTPConn *_conn,
874  char *_buf,ptrdiff_t _size,int _block){
875   struct pollfd   fd;
876   SSL            *ssl_conn;
877   ptrdiff_t       nread;
878   fd.fd=_conn->fd;
879   ssl_conn=_conn->ssl_conn;
880   nread=0;
881   do{
882     int err;
883     if(ssl_conn!=NULL){
884       int ret;
885       ret=SSL_read(ssl_conn,_buf+nread,_size-nread);
886       if(ret>0){
887         /*Read some data.
888           Keep going to see if there's more.*/
889         nread+=ret;
890         continue;
891       }
892       /*Connection closed.*/
893       else if(ret==0)break;
894       /*If we already read some data, return it right now.*/
895       if(nread>0)break;
896       err=SSL_get_error(ssl_conn,ret);
897       if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
898       /*Yes, renegotiations can cause SSL_read() to block for writing.*/
899       else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
900       else return 0;
901     }
902     else{
903       ssize_t ret;
904       errno=0;
905       ret=read(fd.fd,_buf+nread,_size-nread);
906       if(ret>0){
907         /*Read some data.
908           Keep going to see if there's more.*/
909         nread+=ret;
910         continue;
911       }
912       /*If we already read some data, return it right now.*/
913       if(nread>0)break;
914       err=errno;
915       if(err!=EAGAIN&&err!=EWOULDBLOCK)return 0;
916       fd.events=POLLIN;
917     }
918     if(!_block)break;
919     /*Need to wait to get any data at all.*/
920     if(poll(&fd,1,-1)==-1)return 0;
921   }
922   while(nread<_size);
923   return nread;
924 }
925
926 /*Reads the entirety of a response to an HTTP request into a buffer.
927   Actual parsing and validation is done later.*/
928 static int op_http_conn_read_response(OpusHTTPConn *_conn,
929  char *_buf,int _size){
930   /*The remaining size of the buffer.*/
931   int size;
932   /*How many characters we've yet to see from the "\r\n\r\n" terminator.*/
933   int state;
934   size=_size;
935   state=4;
936   while(size>=state){
937     ptrdiff_t ret;
938     int       len;
939     ret=op_http_conn_read(_conn,_buf,state,1);
940     if(ret<=0)return OP_FALSE;
941     /*We read some data.*/
942     _buf+=ret;
943     size-=ret;
944     len=_size-size;
945     /*Make sure the starting characters are "HTTP".
946       Otherwise we could wind up waiting forever for a response from
947        something that is not an HTTP server.*/
948     if(len-ret<4&&op_strncasecmp(_buf-len,"HTTP",OP_MIN(len,4))!=0){
949       return OP_FALSE;
950     }
951     /*How far along on the "\r\n\r\n" terminator are we?*/
952     if(*(_buf-1)=='\n'){
953       if(len>=2&&*(_buf-2)=='\r'){
954         if(len>=4&&*(_buf-3)=='\n'&&*(_buf-4)=='\r')return len;
955         state=2;
956       }
957       else state=4;
958     }
959     else if(*(_buf-1)=='\r'){
960       state=3;
961       if(len>=3&&*(_buf-2)=='\n'&&*(_buf-3)=='\r')state=1;
962     }
963     else state=4;
964   }
965   /*Not enough space left in the buffer to add the characters we'd need to get
966      a valid terminator.*/
967   return OP_EIMPL;
968 }
969
970 /*The number of redirections at which we give up.
971   The value here is the current default in Firefox.
972   RFC 2068 mandated a maximum of 5, but RFC 2616 relaxed that to "a client
973    SHOULD detect infinite redirection loops."
974   Fortunately, 20 is less than infinity.*/
975 # define OP_REDIRECT_LIMIT (20)
976
977 /*The maximum size of a response message (before the body).
978   Responses larger than this will be discarded.*/
979 # define OP_RESPONSE_SIZE_MAX (1024)
980
981 # define OP_HTTP_DIGIT "01234567890"
982
983 /*The Reason-Phrase is not allowed to contain control characters, except
984    horizontal tab (HT).*/
985 # define OP_HTTP_CREASON_PHRASE \
986  "\001\002\003\004\005\006\007\010\012\013\014\015\016\017\020\021" \
987  "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
988
989 # define OP_HTTP_CTLS \
990  "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020" \
991  "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
992
993 /*These also include ' ' and '\t', but we get those from CTLS.*/
994 # define OP_HTTP_SEPARATORS "\"(),/:;<=>?@[\\]{}"
995
996 /*TEXT can also include LWS, but that has structure, so we parse it
997    separately.*/
998 # define OP_HTTP_CTOKEN OP_HTTP_CTLS OP_HTTP_SEPARATORS
999
1000 /*Return: The amount of linear white space (LWS) at the start of _s.*/
1001 static int op_http_lwsspn(const char *_s){
1002   int i;
1003   for(i=0;;){
1004     if(_s[0]=='\r'&&_s[1]=='\n'&&(_s[2]=='\t'||_s[2]==' '))i+=3;
1005     else if(_s[i]=='\t'||_s[i]==' ')i++;
1006     else return i;
1007   }
1008 }
1009
1010 static char *op_http_parse_status_line(char **_status_code,char *_response){
1011   char   *next;
1012   char   *status_code;
1013   size_t  d;
1014   /*RFC 2616 Section 6.1 does not say that the tokens in the Status-Line cannot
1015      be separated by optional LWS, but since it specifically calls out where
1016      spaces are to be placed and that CR and LF are not allowed except at the
1017      end, I am assuming this to be true.*/
1018   /*We already validated that this starts with "HTTP"*/
1019   OP_ASSERT(op_strncasecmp(_response,"HTTP",4)==0);
1020   next=_response+4;
1021   if(OP_UNLIKELY(*next++!='/'))return NULL;
1022   d=strspn(next,OP_HTTP_DIGIT);
1023   if(OP_UNLIKELY(d<=0))return NULL;
1024   next+=d;
1025   if(OP_UNLIKELY(*next++!='.'))return NULL;
1026   d=strspn(next,OP_HTTP_DIGIT);
1027   if(OP_UNLIKELY(d<=0))return NULL;
1028   next+=d;
1029   if(OP_UNLIKELY(*next++!=' '))return NULL;
1030   status_code=next;
1031   d=strspn(next,OP_HTTP_DIGIT);
1032   if(OP_UNLIKELY(d!=3))return NULL;
1033   next+=d;
1034   /*The Reason-Phrase can be empty, but the space must be here.*/
1035   if(OP_UNLIKELY(*next++!=' '))return NULL;
1036   next+=strcspn(next,OP_HTTP_CREASON_PHRASE);
1037   if(OP_UNLIKELY(*next++!='\r'))return NULL;
1038   if(OP_UNLIKELY(*next++!='\n'))return NULL;
1039   *_status_code=status_code;
1040   return next;
1041 }
1042
1043 static int op_http_get_next_header(char **_header,char **_cdr,char **_s){
1044   char   *header;
1045   char   *header_end;
1046   char   *cdr;
1047   char   *cdr_end;
1048   char   *next;
1049   size_t  d;
1050   next=*_s;
1051   if(next[0]=='\r'&&next[1]=='\n'){
1052     /*No more headers.*/
1053     *_header=NULL;
1054     *_cdr=NULL;
1055     *_s=NULL;
1056     return 0;
1057   }
1058   header=next+op_http_lwsspn(next);
1059   d=strcspn(header,OP_HTTP_CTOKEN);
1060   if(OP_UNLIKELY(d<=0))return OP_FALSE;
1061   header_end=header+d;
1062   next=header_end+op_http_lwsspn(header_end);
1063   if(OP_UNLIKELY(*next++!=':'))return OP_FALSE;
1064   next+=op_http_lwsspn(next);
1065   cdr=next;
1066   do{
1067     cdr_end=next+strcspn(next,OP_HTTP_CTLS);
1068     next=cdr_end+op_http_lwsspn(cdr_end);
1069   }
1070   while(next>cdr_end);
1071   if(OP_UNLIKELY(*next++!='\r'))return OP_FALSE;
1072   if(OP_UNLIKELY(*next++!='\n'))return OP_FALSE;
1073   *header_end='\0';
1074   *cdr_end='\0';
1075   /*Field names are case-insensitive.*/
1076   op_string_tolower(header);
1077   *_header=header;
1078   *_cdr=cdr;
1079   *_s=next;
1080   return 0;
1081 }
1082
1083 static opus_int64 op_http_parse_nonnegative_int64(const char **_next,
1084  const char *_cdr){
1085   const char *next;
1086   opus_int64  content_length;
1087   int         i;
1088   next=_cdr+strspn(_cdr,OP_HTTP_DIGIT);
1089   *_next=next;
1090   if(OP_UNLIKELY(next<=_cdr))return OP_FALSE;
1091   while(*_cdr=='0')_cdr++;
1092   if(OP_UNLIKELY(next-_cdr>19))return OP_EIMPL;
1093   content_length=0;
1094   for(i=0;i<next-_cdr;i++){
1095     int digit;
1096     digit=_cdr[i]-'0';
1097     /*Check for overflow.*/
1098     if(OP_UNLIKELY(content_length>(OP_INT64_MAX-9)/10+(digit<=7))){
1099       return OP_EIMPL;
1100     }
1101     content_length=content_length*10+digit;
1102   }
1103   return content_length;
1104 }
1105
1106 static opus_int64 op_http_parse_content_length(const char *_cdr){
1107   const char *next;
1108   opus_int64  content_length;
1109   content_length=op_http_parse_nonnegative_int64(&next,_cdr);
1110   if(OP_UNLIKELY(*next!='\0'))return OP_FALSE;
1111   return content_length;
1112 }
1113
1114 static int op_http_parse_content_range(opus_int64 *_first,opus_int64 *_last,
1115  opus_int64 *_length,const char *_cdr){
1116   opus_int64 first;
1117   opus_int64 last;
1118   opus_int64 length;
1119   size_t d;
1120   if(OP_UNLIKELY(op_strncasecmp(_cdr,"bytes",5)!=0))return OP_FALSE;
1121   _cdr+=5;
1122   d=op_http_lwsspn(_cdr);
1123   if(OP_UNLIKELY(d<=0))return OP_FALSE;
1124   _cdr+=d;
1125   if(*_cdr!='*'){
1126     first=op_http_parse_nonnegative_int64(&_cdr,_cdr);
1127     if(OP_UNLIKELY(first<0))return (int)first;
1128     _cdr+=op_http_lwsspn(_cdr);
1129     if(*_cdr++!='-')return OP_FALSE;
1130     _cdr+=op_http_lwsspn(_cdr);
1131     last=op_http_parse_nonnegative_int64(&_cdr,_cdr);
1132     if(OP_UNLIKELY(last<0))return (int)last;
1133     _cdr+=op_http_lwsspn(_cdr);
1134   }
1135   else{
1136     /*This is for a 416 response (Requested range not satisfiable).*/
1137     first=last=-1;
1138     _cdr++;
1139   }
1140   if(OP_UNLIKELY(*_cdr++!='/'))return OP_FALSE;
1141   if(*_cdr!='*'){
1142     length=op_http_parse_nonnegative_int64(&_cdr,_cdr);
1143     if(OP_UNLIKELY(length<0))return (int)length;
1144   }
1145   else{
1146     /*The total length is unspecified.*/
1147     _cdr++;
1148     length=-1;
1149   }
1150   if(OP_UNLIKELY(*_cdr!='\0'))return OP_FALSE;
1151   if(OP_UNLIKELY(last<first))return OP_FALSE;
1152   if(length!=-1&&OP_UNLIKELY(last>=length))return OP_FALSE;
1153   *_first=first;
1154   *_last=last;
1155   *_length=length;
1156   return 0;
1157 }
1158
1159 static int op_http_stream_open(OpusHTTPStream *_stream,const char *_url,
1160  int _flags,const char *_proxy_host,unsigned _proxy_port,
1161  const char *_proxy_user,const char *_proxy_pass){
1162   struct addrinfo *addrs;
1163   const char      *last_host;
1164   unsigned         last_port;
1165   int              nredirs;
1166   int              ret;
1167   if(_proxy_host!=NULL&&OP_UNLIKELY(_proxy_port>65535U))return OP_EINVAL;
1168   last_host=NULL;
1169   ret=op_parse_url(&_stream->url,_url);
1170   if(OP_UNLIKELY(ret<0))return ret;
1171   for(nredirs=0;nredirs<OP_REDIRECT_LIMIT;nredirs++){
1172     char        response[OP_RESPONSE_SIZE_MAX];
1173     char       *next;
1174     char       *status_code;
1175     const char *host;
1176     unsigned    port;
1177     if(_proxy_host==NULL){
1178       host=_stream->url.host;
1179       port=_stream->url.port;
1180     }
1181     else{
1182       host=_proxy_host;
1183       port=_proxy_port;
1184     }
1185     /*If connecting to the same place as last time, don't re-resolve it.*/
1186     addrs=NULL;
1187     if(last_host!=NULL){
1188       if(strcmp(last_host,host)==0&&last_port==port)addrs=&_stream->addr_info;
1189       if(last_host!=_proxy_host)_ogg_free((void *)last_host);
1190     }
1191     last_host=host;
1192     last_port=port;
1193     /*Initialize the SSL library if necessary.*/
1194     if(OP_URL_IS_SSL(&_stream->url)&&_stream->ssl_ctx==NULL){
1195       SSL_CTX *ssl_ctx;
1196       /*We need to establish a CONNECT tunnel to handle https proxying.
1197         This isn't supported yet.*/
1198       if(_proxy_host!=NULL)return OP_EIMPL;
1199       /*TODO: The documentation says this is not re-entrant.*/
1200       SSL_library_init();
1201       /*Needed to get SHA2 algorithms with old OpenSSL versions.*/
1202       OpenSSL_add_ssl_algorithms();
1203       ssl_ctx=SSL_CTX_new(SSLv23_client_method());
1204       if(ssl_ctx==NULL)return OP_EFAULT;
1205       if(!(_flags&OP_SSL_SKIP_CERTIFICATE_CHECK)){
1206         SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
1207       }
1208       _stream->ssl_ctx=ssl_ctx;
1209     }
1210     /*Pop connection 0 off the free list and put it on the LRU list.*/
1211     OP_ASSERT(_stream->free_head==_stream->conns+0);
1212     _stream->lru_head=_stream->conns+0;
1213     _stream->free_head=_stream->conns[0].next;
1214     _stream->conns[0].next=NULL;
1215     /*Actually make the connection.*/
1216     if(addrs!=&_stream->addr_info){
1217       addrs=op_resolve(host,port);
1218       if(OP_UNLIKELY(addrs==NULL))return OP_FALSE;
1219     }
1220     ret=op_http_connect(_stream,_stream->conns+0,addrs);
1221     if(addrs!=&_stream->addr_info)freeaddrinfo(addrs);
1222     if(OP_UNLIKELY(ret<0))return ret;
1223     /*Build the request to send.*/
1224     _stream->request.nbuf=0;
1225     ret=op_sb_append(&_stream->request,"GET ",4);
1226     ret|=op_sb_append_string(&_stream->request,
1227      _proxy_host!=NULL?_url:_stream->url.path);
1228     ret|=op_sb_append(&_stream->request," HTTP/1.0\r\n",11);
1229     ret|=op_sb_append(&_stream->request,"Host: ",6);
1230     ret|=op_sb_append_string(&_stream->request,_stream->url.host);
1231     if(!OP_URL_IS_DEFAULT_PORT(&_stream->url)){
1232       char port[7];
1233       OP_ASSERT(_stream->url.port<=65535U);
1234       sprintf(port,":%u",_stream->url.port);
1235       ret|=op_sb_append_string(&_stream->request,port);
1236     }
1237     ret|=op_sb_append(&_stream->request,"\r\n",2);
1238     /*User-Agents have been a bad idea, so send as little as possible.
1239       RFC 2616 requires at least one token in the User-Agent, which must have
1240        at least one character.*/
1241     ret|=op_sb_append(&_stream->request,"User-Agent: .\r\n",15);
1242     if(_proxy_host!=NULL&&_proxy_user!=NULL&&_proxy_pass!=NULL){
1243       ret|=op_sb_append_basic_auth_header(&_stream->request,
1244        "Proxy-Authorization",_proxy_user,_proxy_pass);
1245     }
1246     if(_stream->url.user!=NULL&&_stream->url.pass!=NULL){
1247       ret|=op_sb_append_basic_auth_header(&_stream->request,
1248        "Authorization",_stream->url.user,_stream->url.pass);
1249     }
1250     /*Always send a Referer [sic] header.
1251       It's common to refuse to serve a resource unless one is present.
1252       We just use the relative "/" URI to suggest we came from the same domain,
1253        as this is the most common check.
1254       This might violate RFC 2616's mandate that the field "MUST NOT be sent if
1255        the Request-URI was obtained from a source that does not have its own
1256        URI, such as input from the user keyboard," but we don't really have any
1257        way to know.*/
1258     /*TODO: Should we update this on redirects?*/
1259     ret|=op_sb_append(&_stream->request,"Referer: /\r\n",12);
1260     /*Always send a Range request header to find out if we're seekable.*/
1261     ret|=op_sb_append(&_stream->request,"Range: bytes=0-\r\n",17);
1262     /*Remember where this is so we can append offsets to it later.*/
1263     _stream->request_tail=_stream->request.nbuf-4;
1264     ret|=op_sb_append(&_stream->request,"\r\n",2);
1265     if(OP_UNLIKELY(ret<0))return ret;
1266     ret=op_http_conn_write_fully(_stream->conns+0,
1267      _stream->request.buf,_stream->request.nbuf);
1268     if(OP_UNLIKELY(ret<0))return ret;
1269     ret=op_http_conn_read_response(_stream->conns+0,
1270      response,sizeof(response)/sizeof(*response));
1271     if(OP_UNLIKELY(ret<0))return ret;
1272     next=op_http_parse_status_line(&status_code,response);
1273     if(next==NULL)return OP_FALSE;
1274     if(status_code[0]=='2'){
1275       opus_int64 content_length;
1276       opus_int64 range_length;
1277       /*We only understand 20x codes.*/
1278       if(status_code[1]!='0')return OP_FALSE;
1279       content_length=-1;
1280       range_length=-1;
1281       for(;;){
1282         char *header;
1283         char *cdr;
1284         ret=op_http_get_next_header(&header,&cdr,&next);
1285         if(OP_UNLIKELY(ret<0))return ret;
1286         if(header==NULL)break;
1287         if(strcmp(header,"content-length")==0){
1288           /*Two Content-Length headers?*/
1289           if(OP_UNLIKELY(content_length!=-1))return OP_FALSE;
1290           content_length=op_http_parse_content_length(cdr);
1291           if(OP_UNLIKELY(content_length<0))return (int)content_length;
1292           /*Make sure the Content-Length and Content-Range headers match.*/
1293           if(range_length!=-1&&OP_UNLIKELY(content_length!=range_length)){
1294             return OP_FALSE;
1295           }
1296         }
1297         else if(strcmp(header,"content-range")==0){
1298           opus_int64 range_first;
1299           opus_int64 range_last;
1300           /*Two Content-Range headers?*/
1301           if(OP_UNLIKELY(range_length!=-1))return OP_FALSE;
1302           ret=op_http_parse_content_range(&range_first,&range_last,
1303            &range_length,cdr);
1304           if(OP_UNLIKELY(ret<0))return ret;
1305           /*"A response with satus code 206 (Partial Content) MUST NOTE
1306              include a Content-Range field with a byte-range-resp-spec of
1307              '*'."*/
1308           if(status_code[2]=='6'
1309            &&(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))){
1310             return OP_FALSE;
1311           }
1312           /*We asked for the entire resource.*/
1313           if(range_length>=0){
1314             /*Quit if we didn't get it.*/
1315             if(range_last>=0&&OP_UNLIKELY(range_last!=range_length-1)){
1316               return OP_FALSE;
1317             }
1318           }
1319           /*If there was no length, use the end of the range.*/
1320           else if(range_last>=0)range_length=range_last+1;
1321           /*Make sure the Content-Length and Content-Range headers match.*/
1322           if(content_length!=-1&&OP_UNLIKELY(content_length!=range_length)){
1323             return OP_FALSE;
1324           }
1325         }
1326       }
1327       switch(status_code[2]){
1328         /*200 OK*/
1329         case '0':break;
1330         /*203 Non-Authoritative Information*/
1331         case '3':break;
1332         /*204 No Content*/
1333         case '4':{
1334           if(content_length!=-1&&OP_UNLIKELY(content_length!=0)){
1335             return OP_FALSE;
1336           }
1337         }break;
1338         /*206 Partial Content*/
1339         case '6':{
1340           /*No Content-Range header.*/
1341           if(OP_UNLIKELY(range_length==-1))return OP_FALSE;
1342           content_length=range_length;
1343           /*The server supports range requests for this resource.
1344             We can seek.*/
1345           _stream->seekable=1;
1346         }break;
1347         /*201 Created: the response "SHOULD include an entity containing a list
1348            of resource characteristics and location(s)," but not an Opus file.
1349           202 Accepted: the response "SHOULD include an indication of request's
1350            current status and either a pointer to a status monitor or some
1351            estimate of when the user can expect the request to be fulfilled,"
1352            but not an Opus file.
1353           205 Reset Content: this "MUST NOT include an entity," meaning no Opus
1354            file.
1355           207...209 are not yet defined, so we don't know how to handle them.*/
1356         default:return OP_FALSE;
1357       }
1358       _stream->content_length=content_length;
1359       _stream->conns[0].pos=0;
1360       _stream->cur_conni=0;
1361       /*The URL has been successfully opened.*/
1362       return 0;
1363     }
1364     /*Shouldn't get 1xx; 4xx and 5xx are both failures (and we don't retry).
1365       Everything else is undefined.*/
1366     else if(status_code[0]!='3')return OP_FALSE;
1367     /*We have some form of redirect request.*/
1368     /*We only understand 30x codes.*/
1369     if(status_code[1]!='0')return OP_FALSE;
1370     switch(status_code[2]){
1371       /*300 Multiple Choices: "If the server has a preferred choice of
1372          representation, it SHOULD include the specific URI for that
1373          representation in the Location field," otherwise we'll fail.*/
1374       case '0':
1375       /*301 Moved Permanently*/
1376       case '1':
1377       /*302 Found*/
1378       case '2':
1379       /*307 Temporary Redirect*/
1380       case '7':break;
1381       /*305 Use Proxy: "The Location field gives the URI of the proxy."
1382         TODO: This shouldn't actually be that hard to do.*/
1383       case '5':return OP_EIMPL;
1384       /*303 See Other: "The new URI is not a substitute reference for the
1385          originally requested resource."
1386         304 Not Modified: "The 304 response MUST NOT contain a message-body."
1387         306 (Unused)
1388         308...309 are not yet defined, so we don't know how to handle them.*/
1389       default:return OP_FALSE;
1390     }
1391     _url=NULL;
1392     for(;;){
1393       char *header;
1394       char *cdr;
1395       ret=op_http_get_next_header(&header,&cdr,&next);
1396       if(OP_UNLIKELY(ret<0))return ret;
1397       if(header==NULL)break;
1398       if(strcmp(header,"location")==0&&OP_LIKELY(_url==NULL))_url=cdr;
1399     }
1400     if(OP_UNLIKELY(_url==NULL))return OP_FALSE;
1401     /*Don't free last_host if it came from the last URL.*/
1402     if(last_host!=_proxy_host)_stream->url.host=NULL;
1403     op_parsed_url_clear(&_stream->url);
1404     ret=op_parse_url(&_stream->url,_url);
1405     if(OP_UNLIKELY(ret<0)){
1406       if(ret==OP_EINVAL)ret=OP_FALSE;
1407       if(last_host!=_proxy_host)_ogg_free((void *)last_host);
1408       return ret;
1409     }
1410     op_http_conn_close(_stream,_stream->conns+0);
1411   }
1412   /*Redirection limit reached.*/
1413   return OP_FALSE;
1414 }
1415
1416 static int op_http_conn_open_pos(OpusHTTPStream *_stream,
1417  OpusHTTPConn *_conn,opus_int64 _pos){
1418   char        response[OP_RESPONSE_SIZE_MAX];
1419   char       *next;
1420   char       *status_code;
1421   opus_int64  range_length;
1422   int         ret;
1423   ret=op_http_connect(_stream,_conn,&_stream->addr_info);
1424   if(OP_UNLIKELY(ret<0))return ret;
1425   /*Build the request to send.*/
1426   _stream->request.nbuf=_stream->request_tail;
1427   ret=op_sb_append_nonnegative_int64(&_stream->request,_pos);
1428   ret|=op_sb_append(&_stream->request,"-\r\n\r\n",5);
1429   if(OP_UNLIKELY(ret<0))return ret;
1430   ret=op_http_conn_write_fully(_conn,
1431    _stream->request.buf,_stream->request.nbuf);
1432   if(OP_UNLIKELY(ret<0))return ret;
1433   ret=op_http_conn_read_response(_conn,
1434    response,sizeof(response)/sizeof(*response));
1435   if(OP_UNLIKELY(ret<0))return ret;
1436   next=op_http_parse_status_line(&status_code,response);
1437   if(next==NULL)return OP_FALSE;
1438   /*We _need_ a 206 Partial Content response.*/
1439   if(strncmp(status_code,"206",3)!=0)return OP_FALSE;
1440   range_length=-1;
1441   for(;;){
1442     char *header;
1443     char *cdr;
1444     ret=op_http_get_next_header(&header,&cdr,&next);
1445     if(OP_UNLIKELY(ret<0))return ret;
1446     if(header==NULL)break;
1447     if(strcmp(header,"content-range")==0){
1448       opus_int64 range_first;
1449       opus_int64 range_last;
1450       /*Two Content-Range headers?*/
1451       if(OP_UNLIKELY(range_length!=-1))return OP_FALSE;
1452       ret=op_http_parse_content_range(&range_first,&range_last,
1453        &range_length,cdr);
1454       if(OP_UNLIKELY(ret<0))return ret;
1455       /*"A response with satus code 206 (Partial Content) MUST NOTE
1456          include a Content-Range field with a byte-range-resp-spec of
1457          '*'."*/
1458       if(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))return OP_FALSE;
1459       /*Quit if we didn't get the offset we asked for.*/
1460       if(range_first!=_pos)return OP_FALSE;
1461       /*We asked for the rest of the resource.*/
1462       if(range_length>=0){
1463         /*Quit if we didn't get it.*/
1464         if(OP_UNLIKELY(range_last!=range_length-1))return OP_FALSE;
1465       }
1466       /*If there was no length, use the end of the range.*/
1467       else if(range_last>=0)range_length=range_last+1;
1468     }
1469   }
1470   /*No Content-Range header.*/
1471   if(OP_UNLIKELY(range_length==-1))return OP_FALSE;
1472   /*Update the content_length if necessary.*/
1473   _stream->content_length=range_length;
1474   _conn->pos=_pos;
1475   _stream->cur_conni=_conn-_stream->conns;
1476   OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conni<OP_NCONNS_MAX);
1477   /*The connection has been successfully opened.*/
1478   return 0;
1479 }
1480
1481 static size_t op_http_stream_read(void *_ptr,size_t _size,size_t _nmemb,
1482  void *_stream){
1483   OpusHTTPStream *stream;
1484   ptrdiff_t       nread;
1485   ptrdiff_t       total;
1486   opus_int64      size;
1487   opus_int64      pos;
1488   int             ci;
1489   stream=(OpusHTTPStream *)_stream;
1490   total=_size*_nmemb;
1491   /*Check for overflow/empty read.*/
1492   if(total==0||total/_size!=_nmemb||total>OP_INT64_MAX)return 0;
1493   ci=stream->cur_conni;
1494   /*No current connection => EOF.*/
1495   if(ci<0)return 0;
1496   pos=stream->conns[ci].pos;
1497   size=stream->content_length;
1498   /*Check for EOF.*/
1499   if(size!=-1){
1500     if(pos>=size)return 0;
1501     /*Check for a short read.*/
1502     if(total>size-pos){
1503       _nmemb=(size-pos)/_size;
1504       total=_size*_nmemb;
1505     }
1506   }
1507   if(_size!=1){
1508     ptrdiff_t n;
1509     nread=0;
1510     /*Read individual items one at a time.*/
1511     do{
1512       ptrdiff_t nread_item;
1513       nread_item=0;
1514       do{
1515         /*Block on the first item, or if we've gotten a partial item.*/
1516         n=op_http_conn_read(stream->conns+ci,
1517          _ptr,_size-nread_item,nread==0||nread_item>0);
1518         pos+=n;
1519         nread_item+=n;
1520       }
1521       while(n>0&&nread_item<(ptrdiff_t)_size);
1522       /*We can still fail to read a whole item if we encounter an error, or if
1523          we hit EOF and didn't know the stream length.
1524         TODO: The former is okay, the latter is not.*/
1525       if(nread_item>=(ptrdiff_t)_size)nread++;
1526       total-=_size;
1527     }
1528     while(n>0&&total>0);
1529   }
1530   else{
1531     nread=op_http_conn_read(stream->conns+ci,_ptr,total,1);
1532     pos+=nread;
1533   }
1534   if(OP_LIKELY(nread>0))stream->conns[ci].pos=pos;
1535   else{
1536     /*We either hit an error or EOF.
1537       Either way, we're done with this connection.*/
1538     op_http_conn_close(stream,stream->conns+ci);
1539     stream->cur_conni=-1;
1540     stream->pos=pos;
1541   }
1542   return nread;
1543 }
1544
1545 /*To this will need to be larger than OP_CHUNK_SIZE to be useful.*/
1546 # define OP_READAHEAD_THRESH (128*1024)
1547 /*16 kB is the largest size OpenSSL will return at once.*/
1548 # define OP_READAHEAD_CHUNK_SIZE (16*1024)
1549
1550 static int op_http_stream_seek(void *_stream,opus_int64 _offset,int _whence){
1551   OpusHTTPStream  *stream;
1552   OpusHTTPConn    *conn;
1553   OpusHTTPConn    *prev;
1554   OpusHTTPConn   **pnext;
1555   OpusHTTPConn   **ppnext;
1556   opus_int64       content_length;
1557   opus_int64       pos;
1558   int              ci;
1559   int              ret;
1560   stream=(OpusHTTPStream *)_stream;
1561   if(!stream->seekable)return -1;
1562   /*If we're seekable, we should have gotten a Content-Length.*/
1563   content_length=stream->content_length;
1564   OP_ASSERT(content_length>=0);
1565   ci=stream->cur_conni;
1566   pos=ci<0?content_length:stream->conns[ci].pos;
1567   switch(_whence){
1568     case SEEK_SET:{
1569       /*Check for overflow:*/
1570       if(_offset<0)return -1;
1571       pos=_offset;
1572     }break;
1573     case SEEK_CUR:{
1574       /*Check for overflow:*/
1575       if(_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
1576       pos+=_offset;
1577     }break;
1578     case SEEK_END:{
1579       /*Check for overflow:*/
1580       if(_offset>content_length||_offset<content_length-OP_INT64_MAX)return -1;
1581       pos=content_length-_offset;
1582     }break;
1583     default:return -1;
1584   }
1585   /*If we seeked past the end of the stream, just disable the active
1586      connection.*/
1587   if(pos>=content_length){
1588     stream->cur_conni=-1;
1589     stream->pos=pos;
1590     return 0;
1591   }
1592   ppnext=NULL;
1593   pnext=&stream->lru_head;
1594   prev=NULL;
1595   conn=stream->lru_head;
1596   while(conn!=NULL){
1597     opus_int64 conn_pos;
1598     /*TODO: Estimate connection open time and current throughput, and compute
1599        the read-ahead threshold accordingly.*/
1600     /*TODO: Expire connections aggressively to avoid server timeouts.*/
1601     conn_pos=conn->pos;
1602     if(pos-OP_READAHEAD_THRESH<=conn_pos&&conn_pos<=pos){
1603       /*Found a suitable connection to re-use.*/
1604       *pnext=conn->next;
1605       conn->next=stream->lru_head;
1606       stream->lru_head=conn;
1607       while(conn_pos<pos){
1608         static char dummy_buf[OP_READAHEAD_CHUNK_SIZE];
1609         ptrdiff_t nread;
1610         nread=op_http_conn_read(conn,dummy_buf,
1611          OP_MIN(pos-conn_pos,OP_READAHEAD_CHUNK_SIZE),1);
1612         if(nread==0)break;
1613         conn_pos+=nread;
1614       }
1615       conn->pos=conn_pos;
1616       /*We failed to read ahead.*/
1617       if(conn_pos<pos){
1618         op_http_conn_close(stream,conn);
1619         /*The connection might have become stale, so keep going.*/
1620         conn=*pnext;
1621         continue;
1622       }
1623       /*Sucessfully resurrected this connection.*/
1624       stream->cur_conni=conn-stream->conns;
1625       return 0;
1626     }
1627     ppnext=pnext;
1628     pnext=&conn->next;
1629     prev=conn;
1630     conn=conn->next;
1631   }
1632   /*No suitable connections.
1633     Open a new one.*/
1634   if(stream->free_head==NULL){
1635     /*All connections in use.
1636       Expire the oldest one.*/
1637     OP_ASSERT(prev!=NULL);
1638     OP_ASSERT(ppnext!=NULL);
1639     OP_ASSERT(prev->next==NULL);
1640     *ppnext=NULL;
1641     prev->next=stream->lru_head;
1642     stream->lru_head=prev;
1643     op_http_conn_close(stream,prev);
1644   }
1645   OP_ASSERT(stream->free_head!=NULL);
1646   conn=stream->free_head;
1647   stream->free_head=conn->next;
1648   conn->next=stream->lru_head;
1649   stream->lru_head=conn;
1650   ret=op_http_conn_open_pos(stream,conn,pos);
1651   if(OP_UNLIKELY(ret<0)){
1652     op_http_conn_close(stream,conn);
1653     return -1;
1654   }
1655   return 0;
1656 }
1657
1658 static opus_int64 op_http_stream_tell(void *_stream){
1659   OpusHTTPStream *stream;
1660   int             ci;
1661   stream=(OpusHTTPStream *)_stream;
1662   ci=stream->cur_conni;
1663   return ci<0?stream->pos:stream->conns[ci].pos;
1664 }
1665
1666 static int op_http_stream_close(void *_stream){
1667   OpusHTTPStream *stream;
1668   stream=(OpusHTTPStream *)_stream;
1669   if(OP_LIKELY(stream!=NULL)){
1670     op_http_stream_clear(stream);
1671     _ogg_free(stream);
1672   }
1673   return 0;
1674 }
1675
1676 static const OpusFileCallbacks OP_HTTP_CALLBACKS={
1677   op_http_stream_read,
1678   op_http_stream_seek,
1679   op_http_stream_tell,
1680   op_http_stream_close
1681 };
1682 #endif
1683
1684 void *op_url_stream_create_with_proxy(OpusFileCallbacks *_cb,const char *_url,
1685  int _flags,const char *_proxy_host,unsigned _proxy_port,
1686  const char *_proxy_user,const char *_proxy_pass){
1687   const char *path;
1688   /*Check to see if this is a valid file: URL.*/
1689   path=op_parse_file_url(_url);
1690   if(path!=NULL){
1691     char *unescaped_path;
1692     void *ret;
1693     unescaped_path=op_string_dup(path);
1694     if(unescaped_path==NULL)return NULL;
1695     ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb");
1696     _ogg_free(unescaped_path);
1697     return ret;
1698   }
1699 #if defined(OP_ENABLE_HTTP)
1700   /*If not, try http/https.*/
1701   else{
1702     OpusHTTPStream *stream;
1703     int             ret;
1704     stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream));
1705     if(stream==NULL)return NULL;
1706     op_http_stream_init(stream);
1707     ret=op_http_stream_open(stream,_url,_flags,
1708      _proxy_host,_proxy_port,_proxy_user,_proxy_pass);
1709     if(OP_UNLIKELY(ret<0)){
1710       op_http_stream_clear(stream);
1711       _ogg_free(stream);
1712       return NULL;
1713     }
1714     *_cb=*&OP_HTTP_CALLBACKS;
1715     return stream;
1716   }
1717 #else
1718   _flags=_flags;
1719   _proxy_host=_proxy_host;
1720   _proxy_port=_proxy_port;
1721   _proxy_user=_proxy_user;
1722   _proxy_pass=_proxy_pass;
1723   return NULL;
1724 #endif
1725 }
1726
1727 void *op_url_stream_create(OpusFileCallbacks *_cb,const char *_url,int _flags){
1728   return op_url_stream_create_with_proxy(_cb,_url,_flags,NULL,0,NULL,NULL);
1729 }