int ILibWebServer_StreamBody(struct ILibWebServer_Session *session, char *buffer, int bufferSize, int userFree, int done)
{
	struct packetheader *hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3);
	char *hex;
	int hexLen;
	int RetVal=0;

	if(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0)
	{
		// 1.0 No Chunk
		if(bufferSize>0)
		{
			RetVal = ILibWebServer_Send_Raw(session,buffer,bufferSize,userFree,done);
		}
		else if(done!=0)
		{
			RetVal = ILibWebServer_RequestAnswered(session);
		}
	}
	else
	{
		// 1.1+ , Chunk
		if(bufferSize>0)
		{
			hex = (char*)MALLOC(16);
			hexLen = sprintf(hex,"%X\r\n",bufferSize);
			RetVal = ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR;

			if(ILibWebServer_Send_Raw(session,hex,hexLen,0,0)!=ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR)
			{
				if(ILibWebServer_Send_Raw(session,buffer,bufferSize,userFree,0)!=ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR)
				{
					RetVal = ILibWebServer_Send_Raw(session,"\r\n",2,1,0);
				}
			}
			
		}
		if(done!=0 && RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT)
		{
			RetVal = ILibWebServer_Send_Raw(session,"0\r\n\r\n",5,1,1);
		}
	}

	return(RetVal);
}
int ILibWebServer_StreamHeader_Raw(struct ILibWebServer_Session *session, int StatusCode,char *StatusData,char *ResponseHeaders, int ResponseHeaders_FREE)
{
	struct packetheader *hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3);
	
	char *buffer;
	int bufferLength;
	int RetVal;

	buffer = (char*)MALLOC(20+strlen(StatusData));
	bufferLength = sprintf(buffer,"HTTP/1.1 %d %s",StatusCode,StatusData);



	RetVal = ILibWebServer_Send_Raw(session,buffer,bufferLength,0,0);
	if(RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT)
	{
		if(!(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0))
		{
			RetVal = ILibWebServer_Send_Raw(session,"\r\nTransfer-Encoding: chunked",28,1,0);
		}
		else
		{
			// Must Close Socket when done
			session->Reserved6=1;
		}
		if(ResponseHeaders!=NULL && RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT)
		{
			RetVal = ILibWebServer_Send_Raw(session,ResponseHeaders,(int)strlen(ResponseHeaders),ResponseHeaders_FREE,0);
		}
		if(RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT)
		{
			return(ILibWebServer_Send_Raw(session,"\r\n\r\n",4,1,0));
		}
		else
		{
			return(RetVal);
		}
	}
	return(RetVal);
}
Example #3
0
void DH_AbortTransfer(DH_TransferStatus transfer_status_handle)
{
	sem_wait(&(transfer_status_handle->syncLock));
	if(transfer_status_handle->RequestToken != NULL)
	{
		transfer_status_handle->Reserved4 = 1;
	}
	sem_post(&(transfer_status_handle->syncLock));
	if(transfer_status_handle->ServerSession!=NULL)
	{
		if(transfer_status_handle->SessionFlag!=0)
		{
			ILibWebServer_Send_Raw(transfer_status_handle->ServerSession,"HTTP/1.1 500 Server Abort\r\n\r\n",29,ILibAsyncSocket_MemoryOwnership_STATIC,1);
		}
		ILibWebServer_DisconnectSession(transfer_status_handle->ServerSession);
	}
}
int ILibWebServer_StreamHeader(struct ILibWebServer_Session *session, struct packetheader *header)
{
	struct packetheader *hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3);
	struct packetheader_field_node *n = header->FirstField;
	char *buffer;
	int bufferLength;
	int RetVal;
	while(n!=NULL)
	{
		if(n->FieldLength==14 && strncasecmp(n->Field,"Content-Length",14)==0)
		{
			break;
		}
		n = n->NextField;
	}

	if(!(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0))
	{
		// Remove Content-Length and Chunk it!
		if(n!=NULL)
		{
			n->Field = "Transfer-Encoding";
			n->FieldLength = 17;
			n->FieldData = "chunked";
			n->FieldDataLength = 7;
		}
		else
		{
			ILibAddHeaderLine(header,"Transfer-Encoding",17,"chunked",7);
		}
	}
	else
	{
		// Check to see if they gave us a Content-Length
		if(n==NULL)
		{
			// Must Close Socket when done
			session->Reserved6=1;
		}
	}
	bufferLength = ILibGetRawPacket(header,&buffer);
	RetVal = ILibWebServer_Send_Raw(session,buffer,bufferLength,0,0);
	ILibDestructPacket(header);
	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 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;
}