📄 ilibwebserver.c
字号:
// //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} if(!(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0)) { // // If this was not an HTTP/1.0 response, then we need to chunk // RetVal = ILibWebServer_Send_Raw(session,"\r\nTransfer-Encoding: chunked",28,1,0); } else { //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} // // Since we are streaming over HTTP/1.0 , we are required to close the socket when done // session->Reserved6=1; //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} } //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} if(ResponseHeaders!=NULL && RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { // // Send the user specified headers // len = (int)strlen(ResponseHeaders); if(len<MAX_HEADER_LENGTH) { RetVal = ILibWebServer_Send_Raw(session,ResponseHeaders,len,ResponseHeaders_FREE,0); } else { pr = ILibParseString(ResponseHeaders,0,len,"\r\n",2); prf = pr->FirstResult; while(prf!=NULL) { if(prf->datalength!=0) { pr2 = ILibParseString(prf->data,0,prf->datalength,":",1); if(pr2->NumResults!=1) { RetVal = ILibWebServer_Send_Raw(session,"\r\n",2,ILibAsyncSocket_MemoryOwnership_STATIC,0); if(RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { RetVal = ILibWebServer_Send_Raw(session,pr2->FirstResult->data,pr2->FirstResult->datalength+1,ILibAsyncSocket_MemoryOwnership_USER,0); if(RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { tempLength = ILibFragmentText(prf->data+pr2->FirstResult->datalength+1,prf->datalength-pr2->FirstResult->datalength-1,"\r\n ",3,MAX_HEADER_LENGTH,&temp); RetVal = ILibWebServer_Send_Raw(session,temp,tempLength,ILibAsyncSocket_MemoryOwnership_CHAIN,0); } else { ILibDestructParserResults(pr2); break; } } else { ILibDestructParserResults(pr2); break; } } ILibDestructParserResults(pr2); } prf = prf->NextResult; } ILibDestructParserResults(pr); } } if(RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { // // Send the Header Terminator // return(ILibWebServer_Send_Raw(session,"\r\n\r\n",4,1,0)); } else { if(RetVal!=0 && session->Reserved10!=NULL) { *(session->Reserved10)=NULL; } return(RetVal); } } // // ToDo: May want to check logic if the sends didn't go through // if(RetVal!=0 && session->Reserved10!=NULL) { *(session->Reserved10)=NULL; } return(RetVal);}/// <summary>/// Streams the HTTP header response on a session/// </summary>/// <para>/// DO NOT specify Transfer-Encoding./// </para>/// <param name="session">The ILibWebServer_Session to send the response on</param>/// <param name="header">The headers to return</param>/// <returns>Send Status</returns>int ILibWebServer_StreamHeader(struct ILibWebServer_Session *session, struct packetheader *header){ struct packetheader *hdr; struct packetheader_field_node *n; char *buffer; int bufferLength; int RetVal; if(session==NULL) { ILibDestructPacket(header); return(ILibWebServer_INVALID_SESSION); } hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3); n = header->FirstField; while(n!=NULL) { if(n->FieldLength==14 && strncasecmp(n->Field,"Content-Length",14)==0) { break; } n = n->NextField; }//{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} if(!(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0)) { // // If this isn't an HTTP/1.0 connection, remove content-length, and chunk the response // if(n!=NULL) { // // This is replacing the Content-Length header with a Transfer-Encoding header // n->Field = "Transfer-Encoding"; n->FieldLength = 17; n->FieldData = "chunked"; n->FieldDataLength = 7; } else { // // Since Content-Length wasn't specified, we just add the Transfer-Encoding header // ILibAddHeaderLine(header,"Transfer-Encoding",17,"chunked",7); } } else {//{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} // Check to see if they gave us a Content-Length if(n==NULL) { // // If it wasn't, we'll set the CloseOverrideFlag, because in order to be compliant // we must close the socket when done // session->Reserved6=1; }//{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} }//{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} // // Grab the bytes and send it // bufferLength = ILibGetRawPacket(header,&buffer); // // Since ILibGetRawPacket allocates memory, we give ownership to the MicroStack, and // let it take care of it // RetVal = ILibWebServer_Send_Raw(session,buffer,bufferLength,0,0); ILibDestructPacket(header); if(RetVal!=0 && session->Reserved10!=NULL) { *(session->Reserved10)=NULL; } return(RetVal);}/// <summary>/// Streams the HTTP body on a session/// </summary>/// <param name="session">The ILibWebServer_Session to send the response on</param>/// <param name="buffer">The buffer to send</param>/// <param name="bufferSize">The size of the buffer</param>/// <param name="userFree">The ownership flag of the buffer</param>/// <param name="done">Flag indicating if this is everything</param>int ILibWebServer_StreamBody(struct ILibWebServer_Session *session, char *buffer, int bufferSize, int userFree, int done){ struct packetheader *hdr; char *hex; int hexLen; int RetVal=0; if(session==NULL) { if(userFree==ILibAsyncSocket_MemoryOwnership_CHAIN) {free(buffer);} return(ILibWebServer_INVALID_SESSION); } hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3); //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} if(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0) { //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} // // This is HTTP/1.0 , so we don't need to do anything special // if(bufferSize>0) { // // If there is actually something to send, then send it // RetVal = ILibWebServer_Send_Raw(session,buffer,bufferSize,userFree,done); } else if(done!=0) { // // Nothing to send? // RetVal = ILibWebServer_RequestAnswered(session); } //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} } else { // // This is HTTP/1.1+ , so we need to chunk the body // if(bufferSize>0) { // // Calculate the length of the body in hex, and create the chunk header // hex = (char*)malloc(16); hexLen = sprintf(hex,"%X\r\n",bufferSize); RetVal = ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR; // // Send the chunk header // if(ILibWebServer_Send_Raw(session,hex,hexLen,0,0)!=ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR) { // // Send the data // if(ILibWebServer_Send_Raw(session,buffer,bufferSize,userFree,0)!=ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR) { // // The data must be terminated with a CRLF, (don't ask why, it just does) // RetVal = ILibWebServer_Send_Raw(session,"\r\n",2,1,0); } else { RetVal = ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR; } } else { RetVal = ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR; } // // These protections with the ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR check is // to prevent broken pipe errors // } if(done!=0 && RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { // // Terminate the chunk // RetVal = ILibWebServer_Send_Raw(session,"0\r\n\r\n",5,1,1); } } //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} if(RetVal!=0 && session->Reserved10!=NULL) { *(session->Reserved10)=NULL; } return(RetVal);}/// <summary>/// Returns the remote interface of an HTTP session/// </summary>/// <param name="session">The ILibWebServer_Session to query</param>/// <returns>The remote interface</returns>int ILibWebServer_GetRemoteInterface(struct ILibWebServer_Session *session){ return(ILibAsyncSocket_GetRemoteInterface(session->Reserved2));}/// <summary>/// Returns the local interface of an HTTP session/// </summary>/// <param name="session">The ILibWebServer_Session to query</param>/// <returns>The local interface</returns>int ILibWebServer_GetLocalInterface(struct ILibWebServer_Session *session){ return(ILibAsyncSocket_GetLocalInterface(session->Reserved2));}/// <summary>/// Registers a Virtual Directory with the ILibWebServer/// </summary>/// <param name="WebServerToken">The ILibWebServer to register with</param>/// <param name="vd">The virtual directory path</param>/// <param name="vdLength">The length of the path</param>/// <param name="OnVirtualDirectory">The Virtual Directory handler</param>/// <param name="user">User state info to pass on</param>/// <returns>0 if successful, nonzero otherwise</returns>int ILibWebServer_RegisterVirtualDirectory(void *WebServerToken, char *vd, int vdLength, ILibWebServer_VirtualDirectory OnVirtualDirectory, void *user){ struct ILibWebServer_VirDir_Data *data; struct ILibWebServer_StateModule *s = (struct ILibWebServer_StateModule*)WebServerToken; if(s->VirtualDirectoryTable==NULL) { // // If no Virtual Directories have been registered yet, we need to initialize // the lookup table // s->VirtualDirectoryTable = ILibInitHashTree(); } if(ILibHasEntry(s->VirtualDirectoryTable,vd,vdLength)!=0) { // // This Virtual Directory was already registered // return(1); } else { // // Add the necesary info into the lookup table // data = (struct ILibWebServer_VirDir_Data*)malloc(sizeof(struct ILibWebServer_VirDir_Data)); data->callback = (void*)OnVirtualDirectory; data->user = user; ILibAddEntry(s->VirtualDirectoryTable,vd,vdLength,data); } return(0);}/// <summary>/// UnRegisters a Virtual Directory from the ILibWebServer/// </summary>/// <param name="WebServerToken">The ILibWebServer to unregister from</param>/// <param name="vd">The virtual directory path</param>/// <param name="vdLength">The length of the path</param>/// <returns>0 if successful, nonzero otherwise</returns>int ILibWebServer_UnRegisterVirtualDirectory(void *WebServerToken, char *vd, int vdLength){ struct ILibWebServer_StateModule *s = (struct ILibWebServer_StateModule*)WebServerToken; if(ILibHasEntry(s->VirtualDirectoryTable,vd,vdLength)!=0) { // // The virtual directory registry was found, delete it // free(ILibGetEntry(s->VirtualDirectoryTable,vd,vdLength)); ILibDeleteEntry(s->VirtualDirectoryTable,vd,vdLength); return(0); } else { // // Couldn't find the virtual directory registry // return(1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -