DH_TransferStatus DHC_IssuePostRequestFromFile(ILibWebClient_RequestManager request_manager, ILibThreadPool pool, const char* target_uri, const char *file_path, int resume_pos, enum DH_TransferModes requestedTransferMode, const char *mime_type, const char *content_features, void* user_obj, DHC_OnResponseDone callback_response) { DH_TransferStatus RetVal; struct packetheader *h; struct sockaddr_in addr; char host[22]; struct DHC_Data *data = NULL; FILE *f; long fileLength; char *Ip; char *Path; unsigned short Port; ILibReaderWriterLock rwLock = (ILibReaderWriterLock)ILibWebClient_GetUser(request_manager); if(rwLock==NULL) { rwLock = ILibReaderWriterLock_CreateEx(ILibWebClient_GetChain(request_manager)); ILibWebClient_SetUser(request_manager,rwLock); } f = fopen(file_path,"rb"); if(f==NULL) { // // Couldn't open file // return(NULL); } data = (struct DHC_Data*)malloc(sizeof(struct DHC_Data)); memset(data,0,sizeof(struct DHC_Data)); data->TransferMode = requestedTransferMode; data->f = f; data->user = user_obj; data->Callback = callback_response; data->pool = pool; data->buffer = (char*)malloc(DHC_READ_BLOCK_SIZE); data->bufferLength = DHC_READ_BLOCK_SIZE; RetVal = data->TransferStatus = DH_CreateNewTransferStatus(); data->rwLock = rwLock; ILibParseUri((char*)target_uri,&Ip,&Port,&Path); memset(&addr,0,sizeof(struct sockaddr_in)); addr.sin_addr.s_addr = inet_addr(Ip); addr.sin_port = htons(Port); sprintf(host,"%s:%u",Ip,Port); h = ILibCreateEmptyPacket(); ILibSetVersion(h,"1.1",3); ILibSetDirective(h,"POST",4,Path,(int)strlen(Path)); ILibAddHeaderLine(h,"Host",4,host,(int)strlen(host)); ILibAddHeaderLine(h,"Expect",6,"100-Continue",12); if(resume_pos>0) { fseek(f,0,SEEK_END); fileLength = ftell(f); fseek(f,(long)resume_pos,SEEK_SET); DH_AddHeader_ContentRange(h,resume_pos,fileLength-1,fileLength); } if(requestedTransferMode!=DH_TransferMode_Unspecified) { DH_AddHeader_transferMode(h, DH_TransferMode_Bulk); } if(content_features!=NULL) { ILibAddHeaderLine(h,"contentFeatures.dlna.org",24,(char*) content_features,(int)strlen(content_features)); } if(mime_type!=NULL) { ILibAddHeaderLine(h,"Content-Type",12,(char*)mime_type,(int)strlen(mime_type)); } ILibReaderWriterLock_WriteLock(rwLock); switch(data->TransferMode) { case DH_TransferMode_Bulk: ILibWebClient_SetQosForNextRequest(request_manager,ILibAsyncSocket_QOS_BACKGROUND); break; case DH_TransferMode_Streaming: ILibWebClient_SetQosForNextRequest(request_manager,ILibAsyncSocket_QOS_AUDIO_VIDEO); break; } data->token = data->TransferStatus->RequestToken = ILibWebClient_PipelineStreamedRequest(request_manager,&addr,h,&DHC_OnResponse,&DHC_OnSendOK,NULL,data); ILibReaderWriterLock_WriteUnLock(rwLock); free(Ip); free(Path); return(RetVal); }
DH_TransferStatus DHS_SavePostToLocalFile(struct ILibWebServer_Session *session, ILibThreadPool pool, struct packetheader *header, const char *file_name, int append_flag, void *user_obj, DHS_OnResponseDone callback_response) { DH_TransferStatus RetVal = NULL; char *hdr_field = NULL; int temp = 0; FILE *f; struct DH_Data *data = NULL; int Start,End,TotalLength; int needClose = 0; // // Check the append flag // if(append_flag==0 && ILibGetHeaderLine(header,"content-range",13)!=NULL) { ILibWebClient_Parse_ContentRange(ILibGetHeaderLine(header,"content-range",13),&Start,&End,&TotalLength); if(Start!=0) { // // append_flag indicates overwrite, but the header's indicate partial content // this is not allowed // if(ILibGetHeaderLine(header,"Expect",6)==NULL) { needClose = 1; } ILibWebServer_Send_Raw(session,"HTTP/1.1 406 Not Acceptable\r\n\r\n",31,ILibAsyncSocket_MemoryOwnership_STATIC,1); if(needClose!=0) { // If the client did not send "Expect 100 Continue", then the request body may already be in transit, so we must close the socket ILibWebServer_DisconnectSession(session); } return(NULL); } } if(append_flag==0) { f = fopen(file_name,"wb"); } else { f = fopen(file_name,"r+b"); } if(f==NULL) { // // Error // if(ILibGetHeaderLine(header,"Expect",6)==NULL) { needClose = 1; } ILibWebServer_Send_Raw(session,"HTTP/1.1 404 File not found\r\n\r\n",31,ILibAsyncSocket_MemoryOwnership_STATIC,1); if(needClose!=0) { // If the client did not send "Expect 100 Continue", then the request body may already be in transit, so we must close the socket ILibWebServer_DisconnectSession(session); } return(NULL); } data = (struct DH_Data*)malloc(sizeof(struct DH_Data)); memset(data,0,sizeof(struct DH_Data)); data->callback_response = callback_response; data->f = f; data->header = header; data->session = session; data->pool = pool; data->OriginalReceivePtr = session->OnReceive; data->user_object = user_obj; RetVal = data->TransferStatus = DH_CreateNewTransferStatus(); RetVal->ServerSession = session; RetVal->SessionFlag = 1; ILibWebServer_OverrideReceiveHandler(session,&DHS_OnReceive_SavePostToLocalFile); session->User3 = data; session->OnDisconnect = &DHS_OnDisconnect; // // Check to see if we need to advance the file pointer // if(append_flag!=0) { hdr_field = ILibGetHeaderLine(header,"content-range",13); if(hdr_field==NULL) { // // Just append to the end of the file // fseek(f,0,SEEK_END); } else { // // Advance the file pointer the specified amount // int SourceFileLength = 0; ILibWebClient_Parse_ContentRange(hdr_field,&Start,&End,&TotalLength); if(Start==-1 && End==-1 && TotalLength==-1) { // Invalid Range ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1); if(ILibGetHeaderLine(header,"Expect",6)==NULL) { // If the client did not send "Expect 100 Continue", then the request body may already be in transit, so we must close the socket ILibWebServer_DisconnectSession(session); } return(NULL); } else { // Valid Range fseek(f,0,SEEK_END); SourceFileLength = (int)ftell(f); if(SourceFileLength != Start) { ILibWebServer_Send_Raw(session,"HTTP/1.1 409 Conflict\r\n\r\n",25,ILibAsyncSocket_MemoryOwnership_STATIC,1); if(ILibGetHeaderLine(header,"Expect",6)==NULL) { // If the client did not send "Expect 100 Continue", then the request body may already be in transit, so we must close the socket ILibWebServer_DisconnectSession(session); } return(NULL); } } } } if(session->done!=0) { // // All the data is here, so OnReceive won't be called anymore // DHS_OnReceive_SavePostToLocalFile(session,0,header,session->buffer,&temp,session->bufferLength,session->done); } else { hdr_field = ILibGetHeaderLine(header,"Content-Length",14); if(hdr_field!=NULL) { data->TransferStatus->TotalBytesToBeReceived = atol(hdr_field); } // // Check to see if we are supposed to send a 100 Continue response // hdr_field = ILibGetHeaderLine(header,"expect",6); if(hdr_field != NULL && strcasecmp(hdr_field,"100-continue")==0) { // // Send 100-Continue // ILibWebServer_Send_Raw(session,"HTTP/1.1 100 Continue\r\n\r\n",25,ILibAsyncSocket_MemoryOwnership_STATIC,0); } else if(hdr_field != NULL) { // // We don't recognize the expectation // ILibWebServer_Send_Raw(session,"HTTP/1.1 417 Expectation Failed\r\n\r\n",35,ILibAsyncSocket_MemoryOwnership_STATIC,1); if(ILibGetHeaderLine(header,"Expect",6)==NULL) { // If the client did not send "Expect 100 Continue", then the request body may already be in transit, so we must close the socket ILibWebServer_DisconnectSession(session); } RetVal = NULL; } } return(RetVal); }
DH_TransferStatus DHC_IssueRequestAndSave(ILibWebClient_RequestManager request_manager, ILibThreadPool pool, const char *file_path, long append_flag, const char *target_uri, enum DH_TransferModes requestedTransferMode, void* user_obj, DHC_OnResponseDone callback_response) { DH_TransferStatus RetVal = NULL; char *IP, *Path; unsigned short Port; struct sockaddr_in dest; char *host; int hostLen; struct packetheader *req; FILE *f; struct DHC_Data *data; ILibReaderWriterLock rwLock = (ILibReaderWriterLock)ILibWebClient_GetUser(request_manager); if(rwLock==NULL) { rwLock = ILibReaderWriterLock_CreateEx(ILibWebClient_GetChain(request_manager)); ILibWebClient_SetUser(request_manager,rwLock); } memset(&dest,0,sizeof(struct sockaddr_in)); if(append_flag==0) { f = fopen(file_path,"wb"); } else { f = fopen(file_path,"r+b"); } if(f!=NULL) { data = (struct DHC_Data*)malloc(sizeof(struct DHC_Data)); memset(data,0,sizeof(struct DHC_Data)); data->TransferMode = requestedTransferMode; data->f = f; data->manager = request_manager; data->Callback = callback_response; data->pool = pool; data->user = user_obj; data->TransferStatus = DH_CreateNewTransferStatus(); RetVal = data->TransferStatus; data->rwLock = rwLock; req = ILibCreateEmptyPacket(); ILibSetVersion(req,"1.1",3); ILibParseUri((char*)target_uri,&IP,&Port,&Path); dest.sin_addr.s_addr = inet_addr(IP); dest.sin_port = htons(Port); host = (char*)malloc((int)strlen(IP)+10); hostLen = sprintf(host,"%s:%u",IP,Port); ILibAddHeaderLine(req,"Host",4,host,hostLen); ILibSetDirective(req,"GET",3,Path,(int)strlen(Path)); // // Look at the append_flag // if(append_flag==-1) { // // Move to the end of the file // fseek(f,0,SEEK_END); append_flag = ftell(f); } if(append_flag>0) { if(fseek(f,append_flag,SEEK_SET)!=0) { fseek(f,0,SEEK_END); append_flag = ftell(f); } data->StartPosition = append_flag; } if(requestedTransferMode!=DH_TransferMode_Unspecified) { DH_AddHeader_transferMode(req,requestedTransferMode); } data->ActualPacket = req; req = ILibCreateEmptyPacket(); ILibSetVersion(req,"1.1",3); ILibAddHeaderLine(req,"Host",4,host,hostLen); ILibSetDirective(req,"HEAD",4,Path,(int)strlen(Path)); // // Choose a transfer mode that is supported // determine if Range is supported // ILibAddHeaderLine(req,"getcontentFeatures.dlna.org",27,"1",1); ILibReaderWriterLock_WriteLock(rwLock); switch(data->TransferMode) { case DH_TransferMode_Bulk: ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_BACKGROUND); break; case DH_TransferMode_Streaming: ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_AUDIO_VIDEO); break; } data->TransferStatus->RequestToken = data->token = ILibWebClient_PipelineRequest(request_manager,&dest,req,&DH_RequestResponse,data,NULL); ILibReaderWriterLock_WriteUnLock(rwLock); free(host); free(IP); free(Path); } return(RetVal); }
DH_TransferStatus DHS_RespondWithLocalFile(struct ILibWebServer_Session *session, ILibThreadPool pool, struct packetheader *header, size_t buffer_size, const char *file_name, unsigned int supported_transfer_mode, const char *mime_type, const char *content_features, const char* ifo_uri, void *user_obj, DHS_OnResponseDone callback_response) { DH_TransferStatus retval = NULL; FILE *f; struct DH_Data *data = NULL; struct packetheader *resp = NULL; char *ifo, *cf = NULL; long RangeStart,RangeLength,FileLength; char len[255]; enum ILibWebClient_Range_Result RangeResult = 0; enum DH_TransferModes transferMode; if(session->done==0) { // // If the get request wasn't completely received yet, then we don't need to do anything yet // return NULL; } f = fopen(file_name,"rb"); if(f!=NULL) { data = (struct DH_Data*)malloc(sizeof(struct DH_Data)); memset(data,0,sizeof(struct DH_Data)); resp = ILibCreateEmptyPacket(); ILibSetVersion(resp,"1.1",3); fseek(f,0,SEEK_END); FileLength = ftell(f); fseek(f,0,SEEK_SET); cf = ILibGetHeaderLine(header,"getcontentFeatures.dlna.org",27); if(cf!= NULL && memcmp(cf, "1", 1)!=0) { ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); } transferMode = DH_GetRequestedTransferMode(header); if( ((transferMode == DH_TransferMode_Bulk) || (transferMode == DH_TransferMode_Interactive)) && ((ILibGetHeaderLine(header,"TimeSeekRange.dlna.org",22)!=NULL) || (ILibGetHeaderLine(header,"PlaySpeed.dlna.org",18)!=NULL) || (ILibGetHeaderLine(header,"realTimeInfo.dlna.org",21)!=NULL) ) ) { ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); } if(ILibGetHeaderLine(header,"Range",5)!=NULL) { RangeResult = ILibWebClient_Parse_Range(ILibGetHeaderLine(header,"Range",5),&RangeStart,&RangeLength,FileLength); switch(RangeResult) { case ILibWebClient_Range_Result_OK: fseek(f,RangeStart,SEEK_SET); data->BytesLeft = RangeLength; ILibSetStatusCode(resp,206,"Partial Content",15); DH_AddHeader_ContentRange(resp,RangeStart,(RangeStart+RangeLength)-1,FileLength); break; case ILibWebClient_Range_Result_INVALID_RANGE: ILibWebServer_Send_Raw(session,"HTTP/1.1 416 Invalid Range\r\n\r\n",30,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); break; case ILibWebClient_Range_Result_BAD_REQUEST: ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); break; } } else if(ILibGetHeaderLine(header,"TimeSeekRange.dlna.org",22)!=NULL) { ILibWebServer_Send_Raw(session,"HTTP/1.1 406 Time-based seek not supported\r\n\r\n",46,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); } else if(ILibGetHeaderLine(header,"PlaySpeed.dlna.org",18)!=NULL) { ILibWebServer_Send_Raw(session,"HTTP/1.1 406 PlaySpeeds not supported\r\n\r\n",41,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); } else { ILibSetStatusCode(resp,200,"OK",2); data->BytesLeft = FileLength; sprintf(len,"%ld",data->BytesLeft); ILibAddHeaderLine(resp,"Content-Length",14,len,(int)strlen(len)); ILibAddHeaderLine(resp,"Accept-Ranges",13,"bytes",5); } if(transferMode == DH_TransferMode_Unspecified && mime_type != NULL) { if(ILibString_StartsWith(mime_type, (int) strlen(mime_type), "video/", 6) != 0) { DH_AddHeader_transferMode(resp, DH_TransferMode_Streaming); } else if(ILibString_StartsWith(mime_type, (int) strlen(mime_type), "audio/", 6) != 0) { DH_AddHeader_transferMode(resp, DH_TransferMode_Streaming); } else if(ILibString_StartsWith(mime_type, (int) strlen(mime_type), "image/", 6) != 0) { DH_AddHeader_transferMode(resp, DH_TransferMode_Interactive); } } else if(!(transferMode & supported_transfer_mode)) { // // Specified transfer mode is not supported // ILibWebServer_Send_Raw(session,"HTTP/1.1 406 Not Acceptable\r\n\r\n",31,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(f); free(data); ILibDestructPacket(resp); return(NULL); } else { DH_AddHeader_transferMode(resp,transferMode); } data->callback_response = callback_response; data->f = f; data->header = header; data->session = session; data->pool = pool; data->TransferStatus = retval = DH_CreateNewTransferStatus(); data->TransferStatus->TotalBytesToBeSent = data->BytesLeft; data->user_object = user_obj; retval->ServerSession = session; session->OnDisconnect = &DH_Disconnect; if(content_features!=NULL) { ILibAddHeaderLine(resp,"contentFeatures.dlna.org",24,(char*) content_features,(int)strlen(content_features)); } if(mime_type!=NULL) { ILibAddHeaderLine(resp,"Content-Type",12,(char*)mime_type,(int)strlen(mime_type)); } else { ILibAddHeaderLine(resp,"Content-Type",12,(char*)DHS_DEFAULT_MIMETYPE,(int)strlen(DHS_DEFAULT_MIMETYPE)); } if(ifo_uri!=NULL) { ifo = (char*)malloc((int)strlen(ifo_uri)+25); sprintf(ifo,"ifoFileURI.dlna.org=\"%s\"",ifo_uri); ILibAddHeaderLine(resp,"PRAGMA",6,ifo,(int)strlen(ifo)); free(ifo); } ILibWebServer_StreamHeader(session,resp); if(header->DirectiveLength==4 && strncasecmp(header->Directive,"HEAD",4)==0) { ILibWebServer_StreamBody(session,NULL,0,ILibAsyncSocket_MemoryOwnership_STATIC,1); fclose(data->f); data->f = NULL; DH_DestroyTransferStatus(data->TransferStatus); free(data); session->OnDisconnect = NULL; return(NULL); } else { lock_init(&(data->SendStatusLock),0,1); ILibThreadPool_QueueUserWorkItem(pool,data,&DH_Pool); } } else { // // Error opening file // ILibWebServer_Send_Raw(session,"HTTP/1.1 404 File Not Found\r\n\r\n",31,ILibAsyncSocket_MemoryOwnership_STATIC,1); } return retval; }