//! If this function succeeds you must closesocket stream->fd static int http_streaming_start(stream_t *stream, int* file_format) { HTTP_header_t *http_hdr = NULL; int fd = stream->fd; int res = STREAM_UNSUPPORTED; int redirect = 0; int auth_retry=0; int seekable=0; char *content_type; const char *content_length; char *next_url; URL_t *url = stream->streaming_ctrl->url; do { redirect = 0; if (fd >= 0) closesocket(fd); fd = http_send_request( url, 0 ); if( fd<0 ) { goto err_out; } http_free(http_hdr); http_hdr = http_read_response( fd ); if( http_hdr==NULL ) { goto err_out; } if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { http_debug_hdr( http_hdr ); } // Check if we can make partial content requests and thus seek in http-streams if( http_hdr!=NULL && http_hdr->status_code==200 ) { const char *accept_ranges = http_get_field(http_hdr,"Accept-Ranges"); const char *server = http_get_field(http_hdr, "Server"); if (accept_ranges) seekable = strncmp(accept_ranges,"bytes",5)==0; else if (server && (strcmp(server, "gvs 1.0") == 0 || strncmp(server, "MakeMKV", 7) == 0)) { // HACK for youtube and MakeMKV incorrectly claiming not to support seeking mp_msg(MSGT_NETWORK, MSGL_WARN, "Broken webserver, incorrectly claims to not support Accept-Ranges\n"); seekable = 1; } } print_icy_metadata(http_hdr); // Check if the response is an ICY status_code reason_phrase if( !strcasecmp(http_hdr->protocol, "ICY") || http_get_field(http_hdr, "Icy-MetaInt") ) { switch( http_hdr->status_code ) { case 200: { // OK char *field_data; // If content-type == video/nsv we most likely have a winamp video stream // otherwise it should be mp3. if there are more types consider adding mime type // handling like later if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "video/nsv") || !strcmp(field_data, "misc/ultravox"))) *file_format = DEMUXER_TYPE_NSV; else if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "audio/aacp") || !strcmp(field_data, "audio/aac"))) *file_format = DEMUXER_TYPE_AAC; else *file_format = DEMUXER_TYPE_LAVF; res = STREAM_ERROR; goto out; } case 400: // Server Full mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server is full, skipping!\n"); goto err_out; case 401: // Service Unavailable mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return service unavailable, skipping!\n"); goto err_out; case 403: // Service Forbidden mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return 'Service Forbidden'\n"); goto err_out; case 404: // Resource Not Found mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server couldn't find requested stream, skipping!\n"); goto err_out; default: mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: unhandled ICY-Errorcode, contact MPlayer developers!\n"); goto err_out; } } // Assume standard http if not ICY switch( http_hdr->status_code ) { case 200: // OK content_length = http_get_field(http_hdr, "Content-Length"); if (content_length) { mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", content_length); stream->end_pos = atoll(content_length); } // Look if we can use the Content-Type content_type = http_get_field( http_hdr, "Content-Type" ); if( content_type!=NULL ) { unsigned int i; mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type ); // Check in the mime type table for a demuxer type for (i = 0; mime_type_table[i].mime_type != NULL; i++) { if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) { *file_format = mime_type_table[i].demuxer_type; res = seekable; goto out; } } } // Not found in the mime type table, don't fail, // we should try raw HTTP res = seekable; goto out; // Redirect case 301: // Permanently case 302: // Temporarily case 303: // See Other case 307: // Temporarily (since HTTP/1.1) // TODO: RFC 2616, recommand to detect infinite redirection loops next_url = http_get_field( http_hdr, "Location" ); if( next_url!=NULL ) { int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; stream->streaming_ctrl->url = url_redirect( &url, next_url ); if (url_is_protocol(url, "mms")) { res = STREAM_REDIRECTED; goto err_out; } if (!url_is_protocol(url, "http")) { mp_msg(MSGT_NETWORK,MSGL_ERR,"Unsupported http %d redirect to %s protocol\n", http_hdr->status_code, url->protocol); goto err_out; } if (is_ultravox) url_set_protocol(url, "unsv"); redirect = 1; } break; case 401: // Authentication required if( http_authenticate(http_hdr, url, &auth_retry)<0 ) goto err_out; redirect = 1; break; default: mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); goto err_out; } } while( redirect ); err_out: if (fd >= 0) closesocket( fd ); fd = -1; http_free( http_hdr ); http_hdr = NULL; out: stream->streaming_ctrl->data = http_hdr; stream->fd = fd; return res; }
static void *http_request(void* arg) { WEBBLK *webblk; int authok = !http_serv.httpauth; char line[HTTP_PATH_LENGTH]; char *url = NULL; char *pointer; char *strtok_str = NULL; CGITAB *cgient; int content_length = 0; int sock = (int) (uintptr_t) arg; if(!(webblk = malloc(sizeof(WEBBLK)))) http_exit(webblk); memset(webblk,0,sizeof(WEBBLK)); webblk->sock = sock; while (hgets(line, sizeof(line), webblk->sock)) { if (*line == '\r' || *line == '\n') break; if((pointer = strtok_r(line," \t\r\n",&strtok_str))) { if(!strcasecmp(pointer,"GET")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) { webblk->request_type = REQTYPE_GET; url = strdup(pointer); } } else if(!strcasecmp(pointer,"POST")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) { webblk->request_type = REQTYPE_POST; url = strdup(pointer); } } else if(!strcasecmp(pointer,"PUT")) { http_error(webblk,"400 Bad Request", "", "This server does not accept PUT requests"); } else if(!strcasecmp(pointer,"Authorization:")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) authok = http_authenticate(webblk,pointer, strtok_r(NULL," \t\r\n",&strtok_str)); } else if(!strcasecmp(pointer,"Cookie:")) { if((pointer = strtok_r(NULL,"\r\n",&strtok_str))) http_interpret_variable_string(webblk, pointer, VARTYPE_COOKIE); } else if(!strcasecmp(pointer,"Content-Length:")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) content_length = atoi(pointer); } } } webblk->request = url; if(webblk->request_type == REQTYPE_POST && content_length != 0) { char *post_arg; if((pointer = post_arg = malloc(content_length + 1))) { int i; for(i = 0; i < content_length; i++) { *pointer = hgetc(webblk->sock); if(*pointer != '\n' && *pointer != '\r') pointer++; } *pointer = '\0'; http_interpret_variable_string(webblk, post_arg, VARTYPE_POST); free(post_arg); } } if (!authok) { http_error(webblk, "401 Authorization Required", "WWW-Authenticate: Basic realm=\"HERCULES\"\n", "You must be authenticated to use this service"); } if (!url) { http_error(webblk,"400 Bad Request", "", "You must specify a GET or POST request"); } /* anything following a ? in the URL is part of the get arguments */ if ((pointer=strchr(url,'?'))) { *pointer++ = 0; http_interpret_variable_string(webblk, pointer, VARTYPE_GET); } while(url[0] == '/' && url[1] == '/') url++; webblk->baseurl = url; if(!strcasecmp("/",url)) url = HTTP_WELCOME; if(strncasecmp("/cgi-bin/",url,9)) http_download(webblk,url); else url += 9; while(*url == '/') url++; #if 0 http_dump_cgi_variables(webblk); #endif for(cgient = cgidir; cgient->path; cgient++) { if(!strcmp(cgient->path, url)) { char tbuf[80]; hprintf(webblk->sock,"HTTP/1.0 200 OK\nConnection: close\n"); hprintf(webblk->sock,"Date: %s\n", http_timestring(tbuf,sizeof(tbuf),time(NULL))); (cgient->cgibin) (webblk); http_exit(webblk); } } #if defined(OPTION_DYNAMIC_LOAD) { zz_cgibin dyncgi; if( (dyncgi = HDL_FINDSYM(webblk->baseurl)) ) { char tbuf[80]; hprintf(webblk->sock,"HTTP/1.0 200 OK\nConnection: close\n"); hprintf(webblk->sock,"Date: %s\n", http_timestring(tbuf,sizeof(tbuf),time(NULL))); dyncgi(webblk); http_exit(webblk); } } #endif /*defined(OPTION_DYNAMIC_LOAD)*/ http_error(webblk, "404 File Not Found","", "The requested file was not found"); return NULL; }
static int asf_http_streaming_start( stream_t *stream, int *demuxer_type ) { HTTP_header_t *http_hdr=NULL; URL_t *url = stream->streaming_ctrl->url; asf_http_streaming_ctrl_t *asf_http_ctrl; char buffer[BUFFER_SIZE]; int i, ret; int fd = stream->fd; int done; int auth_retry = 0; asf_http_ctrl = malloc(sizeof(asf_http_streaming_ctrl_t)); if( asf_http_ctrl==NULL ) { mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); return -1; } asf_http_ctrl->streaming_type = ASF_Unknown_e; asf_http_ctrl->request = 1; asf_http_ctrl->audio_streams = asf_http_ctrl->video_streams = NULL; asf_http_ctrl->n_audio = asf_http_ctrl->n_video = 0; stream->streaming_ctrl->data = (void*)asf_http_ctrl; do { done = 1; if( fd>0 ) closesocket( fd ); if( !strcasecmp( url->protocol, "http_proxy" ) ) { if( url->port==0 ) url->port = 8080; } else { if( url->port==0 ) url->port = 80; } fd = connect2Server( url->hostname, url->port, 1); if( fd<0 ) return fd; http_hdr = asf_http_request( stream->streaming_ctrl ); mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request [%s]\n", http_hdr->buffer ); for(i=0; i < (int)http_hdr->buffer_size ; ) { int r = send( fd, http_hdr->buffer+i, http_hdr->buffer_size-i, DEFAULT_SEND_FLAGS ); if(r <0) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_SocketWriteError,strerror(errno)); goto err_out; } i += r; } http_free( http_hdr ); http_hdr = http_new_header(); do { i = recv( fd, buffer, BUFFER_SIZE, 0 ); //printf("read: %d\n", i ); if( i<=0 ) { perror("read"); goto err_out; } http_response_append( http_hdr, buffer, i ); } while( !http_is_header_entire( http_hdr ) ); if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { http_hdr->buffer[http_hdr->buffer_size]='\0'; mp_msg(MSGT_NETWORK,MSGL_DBG2,"Response [%s]\n", http_hdr->buffer ); } ret = asf_http_parse_response(asf_http_ctrl, http_hdr); if( ret<0 ) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_HeaderParseFailed); goto err_out; } switch( asf_http_ctrl->streaming_type ) { case ASF_Live_e: case ASF_Prerecorded_e: case ASF_PlainText_e: if( http_hdr->body_size>0 ) { if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { goto err_out; } } if( asf_http_ctrl->request==1 ) { if( asf_http_ctrl->streaming_type!=ASF_PlainText_e ) { // First request, we only got the ASF header. ret = asf_streaming_parse_header(fd,stream->streaming_ctrl); if(ret < 0) goto err_out; if(asf_http_ctrl->n_audio == 0 && asf_http_ctrl->n_video == 0) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoStreamFound); goto err_out; } asf_http_ctrl->request++; done = 0; } else { done = 1; } } break; case ASF_Redirector_e: if( http_hdr->body_size>0 ) { if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { goto err_out; } } *demuxer_type = DEMUXER_TYPE_PLAYLIST; done = 1; break; case ASF_Authenticate_e: if( http_authenticate( http_hdr, url, &auth_retry)<0 ) return -1; asf_http_ctrl->streaming_type = ASF_Unknown_e; done = 0; break; case ASF_Unknown_e: default: mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_UnknownASFStreamingType); goto err_out; } // Check if we got a redirect. } while(!done); stream->fd = fd; if( asf_http_ctrl->streaming_type==ASF_PlainText_e || asf_http_ctrl->streaming_type==ASF_Redirector_e ) { stream->streaming_ctrl->streaming_read = nop_streaming_read; stream->streaming_ctrl->streaming_seek = nop_streaming_seek; } else { stream->streaming_ctrl->streaming_read = asf_http_streaming_read; stream->streaming_ctrl->streaming_seek = asf_http_streaming_seek; stream->streaming_ctrl->buffering = 1; } stream->streaming_ctrl->status = streaming_playing_e; stream->close = close_s; http_free( http_hdr ); return 0; err_out: if (fd > 0) closesocket(fd); stream->fd = -1; http_free(http_hdr); return -1; }