713c916e306f02a4bffdfd25679340f94fdbfc5c
[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   op_parsed_url_init(&_stream->url);
517   _stream->ssl_ctx=NULL;
518   op_sb_init(&_stream->request);
519   _stream->seekable=0;
520 }
521
522 /*Close the connection at the top of the LRU list.*/
523 static void op_http_conn_close(OpusHTTPStream *_stream,OpusHTTPConn *_conn){
524   op_http_conn_clear(_conn);
525   _conn->ssl_conn=NULL;
526   _conn->fd=-1;
527   OP_ASSERT(_stream->lru_head==_conn);
528   _stream->lru_head=_conn->next;
529   _conn->next=_stream->free_head;
530   _stream->free_head=_conn;
531 }
532
533 static void op_http_stream_clear(OpusHTTPStream *_stream){
534   while(_stream->lru_head!=NULL)op_http_conn_close(_stream,_stream->lru_head);
535   if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx);
536   op_sb_clear(&_stream->request);
537   op_parsed_url_clear(&_stream->url);
538 }
539
540 static struct addrinfo *op_resolve(const char *_host,unsigned _port){
541   struct addrinfo *addrs;
542   struct addrinfo  hints;
543   char             service[6];
544   memset(&hints,0,sizeof(hints));
545   hints.ai_socktype=SOCK_STREAM;
546   OP_ASSERT(_port<=65535U);
547   sprintf(service,"%u",_port);
548   if(OP_LIKELY(!getaddrinfo(_host,service,&hints,&addrs)))return addrs;
549   return NULL;
550 }
551
552 static int op_sock_set_nonblocking(int _fd,int _nonblocking){
553   int flags;
554   flags=fcntl(_fd,F_GETFL);
555   if(OP_UNLIKELY(flags==-1))return flags;
556   if(_nonblocking)flags|=O_NONBLOCK;
557   else flags&=~O_NONBLOCK;
558   return fcntl(_fd,F_SETFL,flags);
559 }
560
561 /*Try to start a connection to the next address in the given list of a given
562    type.
563   _fd:         The socket to connect with.
564   [out] _addr: A pointer to the list of addresses.
565                This will be advanced to the first one that matches the given
566                 address family (possibly the current one).
567   _ai_family:  The address family to connect to.
568   Return: 1        If the connection was successful.
569           0        If the connection is in progress.
570           OP_FALSE If the connection failed and there were no more addresses
571                     left to try.
572                     *_addr will be set to NULL in this case.*/
573 static int op_sock_connect_next(int _fd,
574  struct addrinfo **_addr,int _ai_family){
575   struct addrinfo *addr;
576   addr=*_addr;
577   for(;;){
578     /*Move to the next address of the requested type.*/
579     for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next);
580     *_addr=addr;
581     /*No more: failure.*/
582     if(addr==NULL)return OP_FALSE;
583     if(connect(_fd,addr->ai_addr,addr->ai_addrlen)!=-1)return 1;
584     if(OP_LIKELY(errno==EINPROGRESS))return 0;
585   }
586 }
587
588 typedef int (*op_ssl_step_func)(SSL *_ssl_conn);
589
590 /*Try to run an SSL function to completion (blocking if necessary).*/
591 static int op_do_ssl_step(SSL *_ssl_conn,int _fd,op_ssl_step_func _step){
592   struct pollfd fd;
593   fd.fd=_fd;
594   for(;;){
595     int ret;
596     int err;
597     ret=(*_step)(_ssl_conn);
598     if(ret>=0)return ret;
599     err=SSL_get_error(_ssl_conn,ret);
600     if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
601     else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
602     else return OP_FALSE;
603     if(poll(&fd,1,-1)==-1)return OP_FALSE;
604   }
605 }
606
607 /*The number of address families to try connecting to simultaneously.*/
608 # define OP_NPROTOS (2)
609
610 static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
611  struct addrinfo *_addrs){
612   struct addrinfo *addr;
613   struct addrinfo *addrs[OP_NPROTOS];
614   struct pollfd    fds[OP_NPROTOS];
615   int              ai_family;
616   int              nprotos;
617   int              ret;
618   int              pi;
619   int              pj;
620   for(pi=0;pi<OP_NPROTOS;pi++)addrs[pi]=NULL;
621   addr=_addrs;
622   /*Try connecting via both IPv4 and IPv6 simultaneously, and keep the first
623      one that succeeds.*/
624   for(;addr!=NULL;addr=addr->ai_next){
625     /*Give IPv6 a slight edge by putting it first in the list.*/
626     if(addr->ai_family==AF_INET6){
627       OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in6));
628       if(addrs[0]==NULL)addrs[0]=addr;
629     }
630     else if(addr->ai_family==AF_INET){
631       OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in));
632       if(addrs[1]==NULL)addrs[1]=addr;
633     }
634   }
635   /*Consolidate the list of addresses.*/
636   for(pi=nprotos=0;pi<OP_NPROTOS;pi++){
637     if(addrs[pi]!=NULL){
638       addrs[nprotos]=addrs[pi];
639       nprotos++;
640     }
641   }
642   /*Try to start a connection to each protocol.*/
643   for(pi=0;pi<nprotos;pi++){
644     ai_family=addrs[pi]->ai_family;
645     fds[pi].fd=socket(ai_family,SOCK_STREAM,addrs[pi]->ai_protocol);
646     fds[pi].events=POLLOUT;
647     if(OP_LIKELY(fds[pi].fd!=-1)){
648       if(OP_LIKELY(op_sock_set_nonblocking(fds[pi].fd,1)!=-1)){
649         ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
650         if(ret>1){
651           /*It succeeded right away, so stop.*/
652           nprotos=pi+1;
653           break;
654         }
655         /*Otherwise go on to the next protocol, and skip the clean-up below.*/
656         else if(ret==0)continue;
657         /*Tried all the addresses for this protocol.*/
658       }
659       /*Clean up the socket.*/
660       close(fds[pi].fd);
661     }
662     /*Remove this protocol from the list.*/
663     memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
664     nprotos--;
665     pi--;
666   }
667   /*Wait for one of the connections to finish.*/
668   while(pi>=nprotos&&nprotos>0&&poll(fds,nprotos,-1)!=-1){
669     for(pi=0;pi<nprotos;pi++){
670       socklen_t errlen;
671       int       err;
672       /*Still waiting...*/
673       if(!fds[pi].revents)continue;
674       errlen=sizeof(err);
675       if(getsockopt(fds[pi].fd,SOL_SOCKET,SO_ERROR,&err,&errlen)!=-1&&err==0){
676         /*Success!*/
677         break;
678       }
679       /*Move on to the next address for this protocol.*/
680       ai_family=addrs[pi]->ai_family;
681       addrs[pi]=addrs[pi]->ai_next;
682       ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
683       /*It succeeded right away, so stop.*/
684       if(ret>0)break;
685       /*Otherwise go on to the next protocol, and skip the clean-up below.*/
686       else if(ret==0)continue;
687       /*Tried all the addresses for this protocol.
688         Remove it from the list.*/
689       close(fds[pi].fd);
690       memmove(fds+pi,fds+pi+1,sizeof(*fds)*(nprotos-pi-1));
691       memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
692       nprotos--;
693       pi--;
694     }
695   }
696   /*Close all the other sockets.*/
697   for(pj=0;pj<nprotos;pj++)if(pi!=pj)close(fds[pj].fd);
698   /*If none of them succeeded, we're done.*/
699   if(pi>=nprotos)return OP_FALSE;
700   /*Save this address for future connection attempts.*/
701   if(addrs[pi]!=&_stream->addr_info){
702     memcpy(&_stream->addr_info,addrs[pi],sizeof(_stream->addr_info));
703     _stream->addr_info.ai_addr=&_stream->addr.s;
704     _stream->addr_info.ai_next=NULL;
705     memcpy(&_stream->addr,addrs[pi]->ai_addr,addrs[pi]->ai_addrlen);
706   }
707   if(OP_URL_IS_SSL(&_stream->url)){
708     SSL *ssl_conn;
709     BIO *ssl_bio;
710     /*Start the SSL connection.*/
711     OP_ASSERT(_stream->ssl_ctx!=NULL);
712     ssl_conn=SSL_new(_stream->ssl_ctx);
713     if(OP_LIKELY(ssl_conn!=NULL)){
714       ssl_bio=BIO_new_socket(fds[pi].fd,BIO_NOCLOSE);
715       if(OP_LIKELY(ssl_bio!=NULL)){
716         SSL_set_bio(ssl_conn,ssl_bio,ssl_bio);
717         SSL_set_connect_state(ssl_conn);
718         ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_connect);
719         if(OP_LIKELY(ret>0)){
720           ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_do_handshake);
721           if(OP_LIKELY(ret>0)){
722             _conn->ssl_conn=ssl_conn;
723             _conn->fd=fds[pi].fd;
724             return 0;
725           }
726         }
727         /*If we wanted to shut down cleanly, we would do:
728         op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_shutdown);*/
729       }
730       SSL_free(ssl_conn);
731     }
732     close(fds[pi].fd);
733     return OP_FALSE;
734   }
735   /*Just a normal non-SSL connection.*/
736   _conn->ssl_conn=NULL;
737   _conn->fd=fds[pi].fd;
738   return 0;
739 }
740
741 # define OP_BASE64_LENGTH(_len) (((_len)+2)/3*4)
742
743 static const char BASE64_TABLE[64]={
744   'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
745   'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
746   'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
747   'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
748 };
749
750 static char *op_base64_encode(char *_dst,const char *_src,int _len){
751   unsigned s0;
752   unsigned s1;
753   unsigned s2;
754   int      ngroups;
755   int      i;
756   ngroups=_len/3;
757   for(i=0;i<ngroups;i++){
758     s0=_src[3*i+0];
759     s1=_src[3*i+1];
760     s2=_src[3*i+2];
761     _dst[4*i+0]=BASE64_TABLE[s0>>2];
762     _dst[4*i+1]=BASE64_TABLE[s0&3<<4|s1>>4];
763     _dst[4*i+2]=BASE64_TABLE[s1&15<<2|s2>>6];
764     _dst[4*i+3]=BASE64_TABLE[s2&63];
765   }
766   _len-=3*i;
767   if(_len==1){
768     s0=_src[3*i+0];
769     _dst[4*i+0]=BASE64_TABLE[s0>>2];
770     _dst[4*i+1]=BASE64_TABLE[s0&3<<4];
771     _dst[4*i+2]='=';
772     _dst[4*i+3]='=';
773     i++;
774   }
775   else if(_len==2){
776     s0=_src[3*i+0];
777     s1=_src[3*i+1];
778     _dst[4*i+0]=BASE64_TABLE[s0>>2];
779     _dst[4*i+1]=BASE64_TABLE[s0&3<<4|s1>>4];
780     _dst[4*i+2]=BASE64_TABLE[s1&15<<2];
781     _dst[4*i+3]='=';
782     i++;
783   }
784   _dst[4*i]='\0';
785   return _dst+4*i;
786 }
787
788 /*Construct an HTTP authorization header using RFC 2617's Basic Authentication
789    Scheme and append it to the given string buffer.*/
790 static int op_sb_append_basic_auth_header(OpusStringBuf *_sb,
791  const char *_header,const char *_user,const char *_pass){
792   int user_len;
793   int pass_len;
794   int user_pass_len;
795   int base64_len;
796   int nbuf_total;
797   int ret;
798   ret=op_sb_append_string(_sb,_header);
799   ret|=op_sb_append(_sb,": Basic ",8);
800   user_len=strlen(_user);
801   pass_len=strlen(_pass);
802   if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT;
803   if(OP_UNLIKELY(user_len+pass_len>(INT_MAX>>2)*3-3))return OP_EFAULT;
804   user_pass_len=user_len+1+pass_len;
805   base64_len=OP_BASE64_LENGTH(user_pass_len);
806   /*Stick "user:pass" at the end of the buffer so we can Base64 encode it
807      in-place.*/
808   nbuf_total=_sb->nbuf;
809   if(OP_UNLIKELY(base64_len>INT_MAX-nbuf_total))return OP_EFAULT;
810   nbuf_total+=base64_len;
811   ret|=op_sb_ensure_capacity(_sb,nbuf_total);
812   if(OP_UNLIKELY(ret<0))return ret;
813   _sb->nbuf=nbuf_total-user_pass_len;
814   ret=op_sb_append(_sb,_user,user_len);
815   OP_ASSERT(!ret);
816   ret=op_sb_append(_sb,":",1);
817   OP_ASSERT(!ret);
818   ret=op_sb_append(_sb,_pass,pass_len);
819   OP_ASSERT(!ret);
820   op_base64_encode(_sb->buf+nbuf_total-base64_len,
821    _sb->buf+nbuf_total-user_pass_len,user_pass_len);
822   return op_sb_append(_sb,"\r\n",2);
823 }
824
825 static int op_http_conn_write_fully(OpusHTTPConn *_conn,
826  const char *_buf,int _size){
827   struct pollfd  fd;
828   SSL           *ssl_conn;
829   fd.fd=_conn->fd;
830   ssl_conn=_conn->ssl_conn;
831   while(_size>0){
832     int err;
833     if(ssl_conn!=NULL){
834       int ret;
835       ret=SSL_write(ssl_conn,_buf,_size);
836       if(ret>0){
837         /*Wrote some data.*/
838         _buf+=ret;
839         _size-=ret;
840         continue;
841       }
842       /*Connection closed.*/
843       else if(ret==0)return OP_FALSE;
844       err=SSL_get_error(ssl_conn,ret);
845       /*Yes, renegotiations can cause SSL_write() to block for reading.*/
846       if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
847       else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
848       else return OP_FALSE;
849     }
850     else{
851       ssize_t ret;
852       errno=0;
853       ret=write(fd.fd,_buf,_size);
854       if(ret>0){
855         _buf+=ret;
856         _size-=ret;
857         continue;
858       }
859       err=errno;
860       if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_FALSE;
861       fd.events=POLLOUT;
862     }
863     if(poll(&fd,1,-1)==-1)return OP_FALSE;
864   }
865   return 0;
866 }
867
868 /*Tries to read from the given connection.
869   [out] _buf: Returns the data read.
870   _size:      The size of the buffer.
871   _block      Whether or not to block until some data is retrieved.*/
872 static ptrdiff_t op_http_conn_read(OpusHTTPConn *_conn,
873  char *_buf,ptrdiff_t _size,int _block){
874   struct pollfd   fd;
875   SSL            *ssl_conn;
876   ptrdiff_t       nread;
877   fd.fd=_conn->fd;
878   ssl_conn=_conn->ssl_conn;
879   nread=0;
880   do{
881     int err;
882     if(ssl_conn!=NULL){
883       int ret;
884       ret=SSL_read(ssl_conn,_buf+nread,_size-nread);
885       if(ret>0){
886         /*Read some data.
887           Keep going to see if there's more.*/
888         nread+=ret;
889         continue;
890       }
891       /*Connection closed.*/
892       else if(ret==0)break;
893       /*If we already read some data, return it right now.*/
894       if(nread>0)break;
895       err=SSL_get_error(ssl_conn,ret);
896       if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
897       /*Yes, renegotiations can cause SSL_read() to block for writing.*/
898       else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
899       else return 0;
900     }
901     else{
902       ssize_t ret;
903       errno=0;
904       ret=read(fd.fd,_buf+nread,_size-nread);
905       if(ret>0){
906         /*Read some data.
907           Keep going to see if there's more.*/
908         nread+=ret;
909         continue;
910       }
911       /*If we already read some data, return it right now.*/
912       if(nread>0)break;
913       err=errno;
914       if(err!=EAGAIN&&err!=EWOULDBLOCK)return 0;
915       fd.events=POLLIN;
916     }
917     if(!_block)break;
918     /*Need to wait to get any data at all.*/
919     if(poll(&fd,1,-1)==-1)return 0;
920   }
921   while(nread<_size);
922   return nread;
923 }
924
925 /*Reads the entirety of a response to an HTTP request into a buffer.
926   Actual parsing and validation is done later.*/
927 static int op_http_conn_read_response(OpusHTTPConn *_conn,
928  char *_buf,int _size){
929   /*The remaining size of the buffer.*/
930   int size;
931   /*How many characters we've yet to see from the "\r\n\r\n" terminator.*/
932   int state;
933   size=_size;
934   state=4;
935   while(size>=state){
936     ptrdiff_t ret;
937     int       len;
938     ret=op_http_conn_read(_conn,_buf,state,1);
939     if(ret<=0)return OP_FALSE;
940     /*We read some data.*/
941     _buf+=ret;
942     size-=ret;
943     len=_size-size;
944     /*Make sure the starting characters are "HTTP".
945       Otherwise we could wind up waiting forever for a response from
946        something that is not an HTTP server.*/
947     if(len-ret<4&&op_strncasecmp(_buf-len,"HTTP",OP_MIN(len,4))!=0){
948       return OP_FALSE;
949     }
950     /*How far along on the "\r\n\r\n" terminator are we?*/
951     if(*(_buf-1)=='\n'){
952       if(len>=2&&*(_buf-2)=='\r'){
953         if(len>=4&&*(_buf-3)=='\n'&&*(_buf-4)=='\r')return len;
954         state=2;
955       }
956       else state=4;
957     }
958     else if(*(_buf-1)=='\r'){
959       state=3;
960       if(len>=3&&*(_buf-2)=='\n'&&*(_buf-3)=='\r')state=1;
961     }
962     else state=4;
963   }
964   /*Not enough space left in the buffer to add the characters we'd need to get
965      a valid terminator.*/
966   return OP_EIMPL;
967 }
968
969 /*The number of redirections at which we give up.
970   The value here is the current default in Firefox.
971   RFC 2068 mandated a maximum of 5, but RFC 2616 relaxed that to "a client
972    SHOULD detect infinite redirection loops."
973   Fortunately, 20 is less than infinity.*/
974 # define OP_REDIRECT_LIMIT (20)
975
976 /*The maximum size of a response message (before the body).
977   Responses larger than this will be discarded.*/
978 # define OP_RESPONSE_SIZE_MAX (1024)
979
980 # define OP_HTTP_DIGIT "01234567890"
981
982 /*The Reason-Phrase is not allowed to contain control characters, except
983    horizontal tab (HT).*/
984 # define OP_HTTP_CREASON_PHRASE \
985  "\001\002\003\004\005\006\007\010\012\013\014\015\016\017\020\021" \
986  "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
987
988 # define OP_HTTP_CTLS \
989  "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020" \
990  "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
991
992 /*These also include ' ' and '\t', but we get those from CTLS.*/
993 # define OP_HTTP_SEPARATORS "\"(),/:;<=>?@[\\]{}"
994
995 /*TEXT can also include LWS, but that has structure, so we parse it
996    separately.*/
997 # define OP_HTTP_CTOKEN OP_HTTP_CTLS OP_HTTP_SEPARATORS
998
999 /*Return: The amount of linear white space (LWS) at the start of _s.*/
1000 static int op_http_lwsspn(const char *_s){
1001   int i;
1002   for(i=0;;){
1003     if(_s[0]=='\r'&&_s[1]=='\n'&&(_s[2]=='\t'||_s[2]==' '))i+=3;
1004     else if(_s[i]=='\t'||_s[i]==' ')i++;
1005     else return i;
1006   }
1007 }
1008
1009 static char *op_http_parse_status_line(char **_status_code,char *_response){
1010   char   *next;
1011   char   *status_code;
1012   size_t  d;
1013   /*RFC 2616 Section 6.1 does not say that the tokens in the Status-Line cannot
1014      be separated by optional LWS, but since it specifically calls out where
1015      spaces are to be placed and that CR and LF are not allowed except at the
1016      end, I am assuming this to be true.*/
1017   /*We already validated that this starts with "HTTP"*/
1018   OP_ASSERT(op_strncasecmp(_response,"HTTP",4)==0);
1019   next=_response+4;
1020   if(OP_UNLIKELY(*next++!='/'))return NULL;
1021   d=strspn(next,OP_HTTP_DIGIT);
1022   if(OP_UNLIKELY(d<=0))return NULL;
1023   next+=d;
1024   if(OP_UNLIKELY(*next++!='.'))return NULL;
1025   d=strspn(next,OP_HTTP_DIGIT);
1026   if(OP_UNLIKELY(d<=0))return NULL;
1027   next+=d;
1028   if(OP_UNLIKELY(*next++!=' '))return NULL;
1029   status_code=next;
1030   d=strspn(next,OP_HTTP_DIGIT);
1031   if(OP_UNLIKELY(d!=3))return NULL;
1032   next+=d;
1033   /*The Reason-Phrase can be empty, but the space must be here.*/
1034   if(OP_UNLIKELY(*next++!=' '))return NULL;
1035   next+=strcspn(next,OP_HTTP_CREASON_PHRASE);
1036   if(OP_UNLIKELY(*next++!='\r'))return NULL;
1037   if(OP_UNLIKELY(*next++!='\n'))return NULL;
1038   *_status_code=status_code;
1039   return next;
1040 }
1041
1042 static int op_http_get_next_header(char **_header,char **_cdr,char **_s){
1043   char   *header;
1044   char   *header_end;
1045   char   *cdr;
1046   char   *cdr_end;
1047   char   *next;
1048   size_t  d;
1049   next=*_s;
1050   if(next[0]=='\r'&&next[1]=='\n'){
1051     /*No more headers.*/
1052     *_header=NULL;
1053     *_cdr=NULL;
1054     *_s=NULL;
1055     return 0;
1056   }
1057   header=next+op_http_lwsspn(next);
1058   d=strcspn(header,OP_HTTP_CTOKEN);
1059   if(OP_UNLIKELY(d<=0))return OP_FALSE;
1060   header_end=header+d;
1061   next=header_end+op_http_lwsspn(header_end);
1062   if(OP_UNLIKELY(*next++!=':'))return OP_FALSE;
1063   next+=op_http_lwsspn(next);
1064   cdr=next;
1065   do{
1066     cdr_end=next+strcspn(next,OP_HTTP_CTLS);
1067     next=cdr_end+op_http_lwsspn(cdr_end);
1068   }
1069   while(next>cdr_end);
1070   if(OP_UNLIKELY(*next++!='\r'))return OP_FALSE;
1071   if(OP_UNLIKELY(*next++!='\n'))return OP_FALSE;
1072   *header_end='\0';
1073   *cdr_end='\0';
1074   /*Field names are case-insensitive.*/
1075   op_string_tolower(header);
1076   *_header=header;
1077   *_cdr=cdr;
1078   *_s=next;
1079   return 0;
1080 }
1081
1082 static opus_int64 op_http_parse_nonnegative_int64(const char **_next,
1083  const char *_cdr){
1084   const char *next;
1085   opus_int64  content_length;
1086   int         i;
1087   next=_cdr+strspn(_cdr,OP_HTTP_DIGIT);
1088   *_next=next;
1089   if(OP_UNLIKELY(next<=_cdr))return OP_FALSE;
1090   while(*_cdr=='0')_cdr++;
1091   if(OP_UNLIKELY(next-_cdr>19))return OP_EIMPL;
1092   content_length=0;
1093   for(i=0;i<next-_cdr;i++){
1094     int digit;
1095     digit=_cdr[i]-'0';
1096     /*Check for overflow.*/
1097     if(OP_UNLIKELY(content_length>(OP_INT64_MAX-9)/10+(digit<=7))){
1098       return OP_EIMPL;
1099     }
1100     content_length=content_length*10+digit;
1101   }
1102   return content_length;
1103 }
1104
1105 static opus_int64 op_http_parse_content_length(const char *_cdr){
1106   const char *next;
1107   opus_int64  content_length;
1108   content_length=op_http_parse_nonnegative_int64(&next,_cdr);
1109   if(OP_UNLIKELY(*next!='\0'))return OP_FALSE;
1110   return content_length;
1111 }
1112
1113 static int op_http_parse_content_range(opus_int64 *_first,opus_int64 *_last,
1114  opus_int64 *_length,const char *_cdr){
1115   opus_int64 first;
1116   opus_int64 last;
1117   opus_int64 length;
1118   size_t d;
1119   if(OP_UNLIKELY(op_strncasecmp(_cdr,"bytes",5)!=0))return OP_FALSE;
1120   _cdr+=5;
1121   d=op_http_lwsspn(_cdr);
1122   if(OP_UNLIKELY(d<=0))return OP_FALSE;
1123   _cdr+=d;
1124   if(*_cdr!='*'){
1125     first=op_http_parse_nonnegative_int64(&_cdr,_cdr);
1126     if(OP_UNLIKELY(first<0))return (int)first;
1127     _cdr+=op_http_lwsspn(_cdr);
1128     if(*_cdr++!='-')return OP_FALSE;
1129     _cdr+=op_http_lwsspn(_cdr);
1130     last=op_http_parse_nonnegative_int64(&_cdr,_cdr);
1131     if(OP_UNLIKELY(last<0))return (int)last;
1132     _cdr+=op_http_lwsspn(_cdr);
1133   }
1134   else{
1135     /*This is for a 416 response (Requested range not satisfiable).*/
1136     first=last=-1;
1137     _cdr++;
1138   }
1139   if(OP_UNLIKELY(*_cdr++!='/'))return OP_FALSE;
1140   if(*_cdr!='*'){
1141     length=op_http_parse_nonnegative_int64(&_cdr,_cdr);
1142     if(OP_UNLIKELY(length<0))return (int)length;
1143   }
1144   else{
1145     /*The total length is unspecified.*/
1146     _cdr++;
1147     length=-1;
1148   }
1149   if(OP_UNLIKELY(*_cdr!='\0'))return OP_FALSE;
1150   if(OP_UNLIKELY(last<first))return OP_FALSE;
1151   if(length!=-1&&OP_UNLIKELY(last>=length))return OP_FALSE;
1152   *_first=first;
1153   *_last=last;
1154   *_length=length;
1155   return 0;
1156 }
1157
1158 static int op_http_stream_open(OpusHTTPStream *_stream,const char *_url,
1159  int _flags,const char *_proxy_host,unsigned _proxy_port,
1160  const char *_proxy_user,const char *_proxy_pass){
1161   struct addrinfo *addrs;
1162   const char      *last_host;
1163   unsigned         last_port;
1164   int              nredirs;
1165   int              ret;
1166   if(_proxy_host!=NULL&&OP_UNLIKELY(_proxy_port>65535U))return OP_EINVAL;
1167   last_host=NULL;
1168   ret=op_parse_url(&_stream->url,_url);
1169   if(OP_UNLIKELY(ret<0))return ret;
1170   for(nredirs=0;nredirs<OP_REDIRECT_LIMIT;nredirs++){
1171     char        response[OP_RESPONSE_SIZE_MAX];
1172     char       *next;
1173     char       *status_code;
1174     const char *host;
1175     unsigned    port;
1176     if(_proxy_host==NULL){
1177       host=_stream->url.host;
1178       port=_stream->url.port;
1179     }
1180     else{
1181       host=_proxy_host;
1182       port=_proxy_port;
1183     }
1184     /*If connecting to the same place as last time, don't re-resolve it.*/
1185     addrs=NULL;
1186     if(last_host!=NULL){
1187       if(strcmp(last_host,host)==0&&last_port==port)addrs=&_stream->addr_info;
1188       if(last_host!=_proxy_host)_ogg_free((void *)last_host);
1189     }
1190     last_host=host;
1191     last_port=port;
1192     /*Initialize the SSL library if necessary.*/
1193     if(OP_URL_IS_SSL(&_stream->url)&&_stream->ssl_ctx==NULL){
1194       SSL_CTX *ssl_ctx;
1195       /*We need to establish a CONNECT tunnel to handle https proxying.
1196         This isn't supported yet.*/
1197       if(_proxy_host!=NULL)return OP_EIMPL;
1198       /*TODO: The documentation says this is not re-entrant.*/
1199       SSL_library_init();
1200       /*Needed to get SHA2 algorithms with old OpenSSL versions.*/
1201       OpenSSL_add_ssl_algorithms();
1202       ssl_ctx=SSL_CTX_new(SSLv23_client_method());
1203       if(ssl_ctx==NULL)return OP_EFAULT;
1204       if(!(_flags&OP_SSL_SKIP_CERTIFICATE_CHECK)){
1205         SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
1206       }
1207       _stream->ssl_ctx=ssl_ctx;
1208     }
1209     /*Pop connection 0 off the free list and put it on the LRU list.*/
1210     OP_ASSERT(_stream->free_head==_stream->conns+0);
1211     _stream->lru_head=_stream->conns+0;
1212     _stream->free_head=_stream->conns[0].next;
1213     _stream->conns[0].next=NULL;
1214     /*Actually make the connection.*/
1215     if(addrs!=&_stream->addr_info){
1216       addrs=op_resolve(host,port);
1217       if(OP_UNLIKELY(addrs==NULL))return OP_FALSE;
1218     }
1219     ret=op_http_connect(_stream,_stream->conns+0,addrs);
1220     if(addrs!=&_stream->addr_info)freeaddrinfo(addrs);
1221     if(OP_UNLIKELY(ret<0))return ret;
1222     /*Build the request to send.*/
1223     _stream->request.nbuf=0;
1224     ret=op_sb_append(&_stream->request,"GET ",4);
1225     ret|=op_sb_append_string(&_stream->request,
1226      _proxy_host!=NULL?_url:_stream->url.path);
1227     ret|=op_sb_append(&_stream->request," HTTP/1.0\r\n",11);
1228     ret|=op_sb_append(&_stream->request,"Host: ",6);
1229     ret|=op_sb_append_string(&_stream->request,_stream->url.host);
1230     if(!OP_URL_IS_DEFAULT_PORT(&_stream->url)){
1231       char port[7];
1232       OP_ASSERT(_stream->url.port<=65535U);
1233       sprintf(port,":%u",_stream->url.port);
1234       ret|=op_sb_append_string(&_stream->request,port);
1235     }
1236     ret|=op_sb_append(&_stream->request,"\r\n",2);
1237     /*User-Agents have been a bad idea, so send as little as possible.
1238       RFC 2616 requires at least one token in the User-Agent, which must have
1239        at least one character.*/
1240     ret|=op_sb_append(&_stream->request,"User-Agent: .\r\n",15);
1241     if(_proxy_host!=NULL&&_proxy_user!=NULL&&_proxy_pass!=NULL){
1242       ret|=op_sb_append_basic_auth_header(&_stream->request,
1243        "Proxy-Authorization",_proxy_user,_proxy_pass);
1244     }
1245     if(_stream->url.user!=NULL&&_stream->url.pass!=NULL){
1246       ret|=op_sb_append_basic_auth_header(&_stream->request,
1247        "Authorization",_stream->url.user,_stream->url.pass);
1248     }
1249     /*Always send a Referer [sic] header.
1250       It's common to refuse to serve a resource unless one is present.
1251       We just use the relative "/" URI to suggest we came from the same domain,
1252        as this is the most common check.
1253       This might violate RFC 2616's mandate that the field "MUST NOT be sent if
1254        the Request-URI was obtained from a source that does not have its own
1255        URI, such as input from the user keyboard," but we don't really have any
1256        way to know.*/
1257     /*TODO: Should we update this on redirects?*/
1258     ret|=op_sb_append(&_stream->request,"Referer: /\r\n",12);
1259     /*Always send a Range request header to find out if we're seekable.*/
1260     ret|=op_sb_append(&_stream->request,"Range: bytes=0-\r\n",17);
1261     /*Remember where this is so we can append offsets to it later.*/
1262     _stream->request_tail=_stream->request.nbuf-4;
1263     ret|=op_sb_append(&_stream->request,"\r\n",2);
1264     if(OP_UNLIKELY(ret<0))return ret;
1265     ret=op_http_conn_write_fully(_stream->conns+0,
1266      _stream->request.buf,_stream->request.nbuf);
1267     if(OP_UNLIKELY(ret<0))return ret;
1268     ret=op_http_conn_read_response(_stream->conns+0,
1269      response,sizeof(response)/sizeof(*response));
1270     if(OP_UNLIKELY(ret<0))return ret;
1271     next=op_http_parse_status_line(&status_code,response);
1272     if(next==NULL)return OP_FALSE;
1273     if(status_code[0]=='2'){
1274       opus_int64 content_length;
1275       opus_int64 range_length;
1276       /*We only understand 20x codes.*/
1277       if(status_code[1]!='0')return OP_FALSE;
1278       content_length=-1;
1279       range_length=-1;
1280       for(;;){
1281         char *header;
1282         char *cdr;
1283         ret=op_http_get_next_header(&header,&cdr,&next);
1284         if(OP_UNLIKELY(ret<0))return ret;
1285         if(header==NULL)break;
1286         if(strcmp(header,"content-length")==0){
1287           /*Two Content-Length headers?*/
1288           if(OP_UNLIKELY(content_length!=-1))return OP_FALSE;
1289           content_length=op_http_parse_content_length(cdr);
1290           if(OP_UNLIKELY(content_length<0))return (int)content_length;
1291           /*Make sure the Content-Length and Content-Range headers match.*/
1292           if(range_length!=-1&&OP_UNLIKELY(content_length!=range_length)){
1293             return OP_FALSE;
1294           }
1295         }
1296         else if(strcmp(header,"content-range")==0){
1297           opus_int64 range_first;
1298           opus_int64 range_last;
1299           /*Two Content-Range headers?*/
1300           if(OP_UNLIKELY(range_length!=-1))return OP_FALSE;
1301           ret=op_http_parse_content_range(&range_first,&range_last,
1302            &range_length,cdr);
1303           if(OP_UNLIKELY(ret<0))return ret;
1304           /*"A response with satus code 206 (Partial Content) MUST NOTE
1305              include a Content-Range field with a byte-range-resp-spec of
1306              '*'."*/
1307           if(status_code[2]=='6'
1308            &&(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))){
1309             return OP_FALSE;
1310           }
1311           /*We asked for the entire resource.*/
1312           if(range_length>=0){
1313             /*Quit if we didn't get it.*/
1314             if(range_last>=0&&OP_UNLIKELY(range_last!=range_length-1)){
1315               return OP_FALSE;
1316             }
1317           }
1318           /*If there was no length, use the end of the range.*/
1319           else if(range_last>=0)range_length=range_last+1;
1320           /*Make sure the Content-Length and Content-Range headers match.*/
1321           if(content_length!=-1&&OP_UNLIKELY(content_length!=range_length)){
1322             return OP_FALSE;
1323           }
1324         }
1325       }
1326       switch(status_code[2]){
1327         /*200 OK*/
1328         case '0':break;
1329         /*203 Non-Authoritative Information*/
1330         case '3':break;
1331         /*204 No Content*/
1332         case '4':{
1333           if(content_length!=-1&&OP_UNLIKELY(content_length!=0)){
1334             return OP_FALSE;
1335           }
1336         }break;
1337         /*206 Partial Content*/
1338         case '6':{
1339           /*No Content-Range header.*/
1340           if(OP_UNLIKELY(range_length==-1))return OP_FALSE;
1341           content_length=range_length;
1342           /*The server supports range requests for this resource.
1343             We can seek.*/
1344           _stream->seekable=1;
1345         }break;
1346         /*201 Created: the response "SHOULD include an entity containing a list
1347            of resource characteristics and location(s)," but not an Opus file.
1348           202 Accepted: the response "SHOULD include an indication of request's
1349            current status and either a pointer to a status monitor or some
1350            estimate of when the user can expect the request to be fulfilled,"
1351            but not an Opus file.
1352           205 Reset Content: this "MUST NOT include an entity," meaning no Opus
1353            file.
1354           207...209 are not yet defined, so we don't know how to handle them.*/
1355         default:return OP_FALSE;
1356       }
1357       _stream->content_length=content_length;
1358       _stream->conns[0].pos=0;
1359       _stream->cur_conni=0;
1360       /*The URL has been successfully opened.*/
1361       return 0;
1362     }
1363     /*Shouldn't get 1xx; 4xx and 5xx are both failures (and we don't retry).
1364       Everything else is undefined.*/
1365     else if(status_code[0]!='3')return OP_FALSE;
1366     /*We have some form of redirect request.*/
1367     /*We only understand 30x codes.*/
1368     if(status_code[1]!='0')return OP_FALSE;
1369     switch(status_code[2]){
1370       /*300 Multiple Choices: "If the server has a preferred choice of
1371          representation, it SHOULD include the specific URI for that
1372          representation in the Location field," otherwise we'll fail.*/
1373       case '0':
1374       /*301 Moved Permanently*/
1375       case '1':
1376       /*302 Found*/
1377       case '2':
1378       /*307 Temporary Redirect*/
1379       case '7':break;
1380       /*305 Use Proxy: "The Location field gives the URI of the proxy."
1381         TODO: This shouldn't actually be that hard to do.*/
1382       case '5':return OP_EIMPL;
1383       /*303 See Other: "The new URI is not a substitute reference for the
1384          originally requested resource."
1385         304 Not Modified: "The 304 response MUST NOT contain a message-body."
1386         306 (Unused)
1387         308...309 are not yet defined, so we don't know how to handle them.*/
1388       default:return OP_FALSE;
1389     }
1390     _url=NULL;
1391     for(;;){
1392       char *header;
1393       char *cdr;
1394       ret=op_http_get_next_header(&header,&cdr,&next);
1395       if(OP_UNLIKELY(ret<0))return ret;
1396       if(header==NULL)break;
1397       if(strcmp(header,"location")==0&&OP_LIKELY(_url==NULL))_url=cdr;
1398     }
1399     if(OP_UNLIKELY(_url==NULL))return OP_FALSE;
1400     /*Don't free last_host if it came from the last URL.*/
1401     if(last_host!=_proxy_host)_stream->url.host=NULL;
1402     op_parsed_url_clear(&_stream->url);
1403     ret=op_parse_url(&_stream->url,_url);
1404     if(OP_UNLIKELY(ret<0)){
1405       if(ret==OP_EINVAL)ret=OP_FALSE;
1406       if(last_host!=_proxy_host)_ogg_free((void *)last_host);
1407       return ret;
1408     }
1409     op_http_conn_close(_stream,_stream->conns+0);
1410   }
1411   /*Redirection limit reached.*/
1412   return OP_FALSE;
1413 }
1414
1415 static int op_http_conn_open_pos(OpusHTTPStream *_stream,
1416  OpusHTTPConn *_conn,opus_int64 _pos){
1417   char        response[OP_RESPONSE_SIZE_MAX];
1418   char       *next;
1419   char       *status_code;
1420   opus_int64  range_length;
1421   int         ret;
1422   ret=op_http_connect(_stream,_conn,&_stream->addr_info);
1423   if(OP_UNLIKELY(ret<0))return ret;
1424   /*Build the request to send.*/
1425   _stream->request.nbuf=_stream->request_tail;
1426   ret=op_sb_append_nonnegative_int64(&_stream->request,_pos);
1427   ret|=op_sb_append(&_stream->request,"-\r\n\r\n",5);
1428   if(OP_UNLIKELY(ret<0))return ret;
1429   ret=op_http_conn_write_fully(_conn,
1430    _stream->request.buf,_stream->request.nbuf);
1431   if(OP_UNLIKELY(ret<0))return ret;
1432   ret=op_http_conn_read_response(_conn,
1433    response,sizeof(response)/sizeof(*response));
1434   if(OP_UNLIKELY(ret<0))return ret;
1435   next=op_http_parse_status_line(&status_code,response);
1436   if(next==NULL)return OP_FALSE;
1437   /*We _need_ a 206 Partial Content response.*/
1438   if(strncmp(status_code,"206",3)!=0)return OP_FALSE;
1439   range_length=-1;
1440   for(;;){
1441     char *header;
1442     char *cdr;
1443     ret=op_http_get_next_header(&header,&cdr,&next);
1444     if(OP_UNLIKELY(ret<0))return ret;
1445     if(header==NULL)break;
1446     if(strcmp(header,"content-range")==0){
1447       opus_int64 range_first;
1448       opus_int64 range_last;
1449       /*Two Content-Range headers?*/
1450       if(OP_UNLIKELY(range_length!=-1))return OP_FALSE;
1451       ret=op_http_parse_content_range(&range_first,&range_last,
1452        &range_length,cdr);
1453       if(OP_UNLIKELY(ret<0))return ret;
1454       /*"A response with satus code 206 (Partial Content) MUST NOTE
1455          include a Content-Range field with a byte-range-resp-spec of
1456          '*'."*/
1457       if(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))return OP_FALSE;
1458       /*Quit if we didn't get the offset we asked for.*/
1459       if(range_first!=_pos)return OP_FALSE;
1460       /*We asked for the rest of the resource.*/
1461       if(range_length>=0){
1462         /*Quit if we didn't get it.*/
1463         if(OP_UNLIKELY(range_last!=range_length-1))return OP_FALSE;
1464       }
1465       /*If there was no length, use the end of the range.*/
1466       else if(range_last>=0)range_length=range_last+1;
1467     }
1468   }
1469   /*No Content-Range header.*/
1470   if(OP_UNLIKELY(range_length==-1))return OP_FALSE;
1471   /*Update the content_length if necessary.*/
1472   _stream->content_length=range_length;
1473   _conn->pos=_pos;
1474   _stream->cur_conni=_conn-_stream->conns;
1475   OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conni<OP_NCONNS_MAX);
1476   /*The connection has been successfully opened.*/
1477   return 0;
1478 }
1479
1480 static size_t op_http_stream_read(void *_ptr,size_t _size,size_t _nmemb,
1481  void *_stream){
1482   OpusHTTPStream *stream;
1483   ptrdiff_t       nread;
1484   ptrdiff_t       total;
1485   opus_int64      size;
1486   opus_int64      pos;
1487   int             ci;
1488   stream=(OpusHTTPStream *)_stream;
1489   total=_size*_nmemb;
1490   /*Check for overflow/empty read.*/
1491   if(total==0||total/_size!=_nmemb||total>OP_INT64_MAX)return 0;
1492   ci=stream->cur_conni;
1493   /*No current connection => EOF.*/
1494   if(ci<0)return 0;
1495   pos=stream->conns[ci].pos;
1496   size=stream->content_length;
1497   /*Check for EOF.*/
1498   if(size!=-1){
1499     if(pos>=size)return 0;
1500     /*Check for a short read.*/
1501     if(total>size-pos){
1502       _nmemb=(size-pos)/_size;
1503       total=_size*_nmemb;
1504     }
1505   }
1506   if(_size!=1){
1507     ptrdiff_t n;
1508     nread=0;
1509     /*Read individual items one at a time.*/
1510     do{
1511       ptrdiff_t nread_item;
1512       nread_item=0;
1513       do{
1514         /*Block on the first item, or if we've gotten a partial item.*/
1515         n=op_http_conn_read(stream->conns+ci,
1516          _ptr,_size-nread_item,nread==0||nread_item>0);
1517         pos+=n;
1518         nread_item+=n;
1519       }
1520       while(n>0&&nread_item<(ptrdiff_t)_size);
1521       /*We can still fail to read a whole item if we encounter an error, or if
1522          we hit EOF and didn't know the stream length.
1523         TODO: The former is okay, the latter is not.*/
1524       if(nread_item>=(ptrdiff_t)_size)nread++;
1525       total-=_size;
1526     }
1527     while(n>0&&total>0);
1528   }
1529   else{
1530     nread=op_http_conn_read(stream->conns+ci,_ptr,total,1);
1531     pos+=nread;
1532   }
1533   if(OP_LIKELY(nread>0))stream->conns[ci].pos=pos;
1534   else{
1535     /*We either hit an error or EOF.
1536       Either way, we're done with this connection.*/
1537     op_http_conn_close(stream,stream->conns+ci);
1538     stream->cur_conni=-1;
1539     stream->pos=pos;
1540   }
1541   return nread;
1542 }
1543
1544 /*To this will need to be larger than OP_CHUNK_SIZE to be useful.*/
1545 # define OP_READAHEAD_THRESH (128*1024)
1546 /*16 kB is the largest size OpenSSL will return at once.*/
1547 # define OP_READAHEAD_CHUNK_SIZE (16*1024)
1548
1549 static int op_http_stream_seek(void *_stream,opus_int64 _offset,int _whence){
1550   OpusHTTPStream  *stream;
1551   OpusHTTPConn    *conn;
1552   OpusHTTPConn    *prev;
1553   OpusHTTPConn   **pnext;
1554   OpusHTTPConn   **ppnext;
1555   opus_int64       content_length;
1556   opus_int64       pos;
1557   int              ci;
1558   int              ret;
1559   stream=(OpusHTTPStream *)_stream;
1560   if(!stream->seekable)return -1;
1561   /*If we're seekable, we should have gotten a Content-Length.*/
1562   content_length=stream->content_length;
1563   OP_ASSERT(content_length>=0);
1564   ci=stream->cur_conni;
1565   pos=ci<0?content_length:stream->conns[ci].pos;
1566   switch(_whence){
1567     case SEEK_SET:{
1568       /*Check for overflow:*/
1569       if(_offset<0)return -1;
1570       pos=_offset;
1571     }break;
1572     case SEEK_CUR:{
1573       /*Check for overflow:*/
1574       if(_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
1575       pos+=_offset;
1576     }break;
1577     case SEEK_END:{
1578       /*Check for overflow:*/
1579       if(_offset>content_length||_offset<content_length-OP_INT64_MAX)return -1;
1580       pos=content_length-_offset;
1581     }break;
1582     default:return -1;
1583   }
1584   /*If we seeked past the end of the stream, just disable the active
1585      connection.*/
1586   if(pos>=content_length){
1587     stream->cur_conni=-1;
1588     stream->pos=pos;
1589     return 0;
1590   }
1591   ppnext=NULL;
1592   pnext=&stream->lru_head;
1593   prev=NULL;
1594   conn=stream->lru_head;
1595   while(conn!=NULL){
1596     opus_int64 conn_pos;
1597     /*TODO: Estimate connection open time and current throughput, and compute
1598        the read-ahead threshold accordingly.*/
1599     /*TODO: Expire connections aggressively to avoid server timeouts.*/
1600     conn_pos=conn->pos;
1601     if(pos-OP_READAHEAD_THRESH<=conn_pos&&conn_pos<=pos){
1602       /*Found a suitable connection to re-use.*/
1603       *pnext=conn->next;
1604       conn->next=stream->lru_head;
1605       stream->lru_head=conn;
1606       while(conn_pos<pos){
1607         static char dummy_buf[OP_READAHEAD_CHUNK_SIZE];
1608         ptrdiff_t nread;
1609         nread=op_http_conn_read(conn,dummy_buf,
1610          OP_MIN(pos-conn_pos,OP_READAHEAD_CHUNK_SIZE),1);
1611         if(nread==0)break;
1612         conn_pos+=nread;
1613       }
1614       conn->pos=conn_pos;
1615       /*We failed to read ahead.*/
1616       if(conn_pos<pos){
1617         op_http_conn_close(stream,conn);
1618         /*The connection might have become stale, so keep going.*/
1619         conn=*pnext;
1620         continue;
1621       }
1622       /*Sucessfully resurrected this connection.*/
1623       stream->cur_conni=conn-stream->conns;
1624       return 0;
1625     }
1626     ppnext=pnext;
1627     pnext=&conn->next;
1628     prev=conn;
1629     conn=conn->next;
1630   }
1631   /*No suitable connections.
1632     Open a new one.*/
1633   if(stream->free_head==NULL){
1634     /*All connections in use.
1635       Expire the oldest one.*/
1636     OP_ASSERT(prev!=NULL);
1637     OP_ASSERT(ppnext!=NULL);
1638     OP_ASSERT(prev->next==NULL);
1639     *ppnext=NULL;
1640     prev->next=stream->lru_head;
1641     stream->lru_head=prev;
1642     op_http_conn_close(stream,prev);
1643   }
1644   OP_ASSERT(stream->free_head!=NULL);
1645   conn=stream->free_head;
1646   stream->free_head=conn->next;
1647   conn->next=stream->lru_head;
1648   stream->lru_head=conn;
1649   ret=op_http_conn_open_pos(stream,conn,pos);
1650   if(OP_UNLIKELY(ret<0)){
1651     op_http_conn_close(stream,conn);
1652     return -1;
1653   }
1654   return 0;
1655 }
1656
1657 static opus_int64 op_http_stream_tell(void *_stream){
1658   OpusHTTPStream *stream;
1659   int             ci;
1660   stream=(OpusHTTPStream *)_stream;
1661   ci=stream->cur_conni;
1662   return ci<0?stream->pos:stream->conns[ci].pos;
1663 }
1664
1665 static int op_http_stream_close(void *_stream){
1666   OpusHTTPStream *stream;
1667   stream=(OpusHTTPStream *)_stream;
1668   if(OP_LIKELY(stream!=NULL)){
1669     op_http_stream_clear(stream);
1670     _ogg_free(stream);
1671   }
1672   return 0;
1673 }
1674
1675 static const OpusFileCallbacks OP_HTTP_CALLBACKS={
1676   op_http_stream_read,
1677   op_http_stream_seek,
1678   op_http_stream_tell,
1679   op_http_stream_close
1680 };
1681 #endif
1682
1683 void *op_url_stream_create_with_proxy(OpusFileCallbacks *_cb,const char *_url,
1684  int _flags,const char *_proxy_host,unsigned _proxy_port,
1685  const char *_proxy_user,const char *_proxy_pass){
1686   const char *path;
1687   /*Check to see if this is a valid file: URL.*/
1688   path=op_parse_file_url(_url);
1689   if(path!=NULL){
1690     char *unescaped_path;
1691     void *ret;
1692     unescaped_path=op_string_dup(path);
1693     if(unescaped_path==NULL)return NULL;
1694     ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb");
1695     _ogg_free(unescaped_path);
1696     return ret;
1697   }
1698 #if defined(OP_ENABLE_HTTP)
1699   /*If not, try http/https.*/
1700   else{
1701     OpusHTTPStream *stream;
1702     int             ret;
1703     stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream));
1704     if(stream==NULL)return NULL;
1705     op_http_stream_init(stream);
1706     ret=op_http_stream_open(stream,_url,_flags,
1707      _proxy_host,_proxy_port,_proxy_user,_proxy_pass);
1708     if(OP_UNLIKELY(ret<0)){
1709       op_http_stream_clear(stream);
1710       _ogg_free(stream);
1711       return NULL;
1712     }
1713     *_cb=*&OP_HTTP_CALLBACKS;
1714     return stream;
1715   }
1716 #else
1717   _flags=_flags;
1718   _proxy_host=_proxy_host;
1719   _proxy_port=_proxy_port;
1720   _proxy_user=_proxy_user;
1721   _proxy_pass=_proxy_pass;
1722   return NULL;
1723 #endif
1724 }
1725
1726 void *op_url_stream_create(OpusFileCallbacks *_cb,const char *_url,int _flags){
1727   return op_url_stream_create_with_proxy(_cb,_url,_flags,NULL,0,NULL,NULL);
1728 }