📄 ilibwebserver.c
字号:
// Add a timed callback, because if we don't receive a request within a specified // amount of time, we want to close the socket, so we don't waste resources // ILibLifeTime_Add(wsm->LifeTime,ws,HTTP_SESSION_IDLE_TIMEOUT,&ILibWebServer_IdleSink,NULL); // // Inform the user that a new session was established // if(wsm->OnSession!=NULL) { wsm->OnSession(ws,wsm->User); }}/// <summary>/// Internal method dispatched from the underlying AsyncServerSocket engine/// </summary>/// <param name="AsyncServerSocketModule">The ILibAsyncServerSocket token</param>/// <param name="ConnectionToken">The ILibAsyncSocket connection token</param>/// <param name="user">The ILibWebServer_Session object</param>static void ILibWebServer_OnDisconnect(void *AsyncServerSocketModule, void *ConnectionToken, void *user){ struct ILibWebServer_Session *ws = (struct ILibWebServer_Session*)user; if(ws->Reserved10 != NULL) { *(ws->Reserved10) = NULL; } // // Reserved4 = RequestAnsweredFlag // Reserved5 = RequestMadeFlag // if(ws->Reserved4!=0 || ws->Reserved5==0) { ILibLifeTime_Remove(((struct ILibWebServer_StateModule*)ws->Parent)->LifeTime,ws); ws->Reserved4=0; } // // Notify the user that this session disconnected // if(ws->OnDisconnect!=NULL) { ws->OnDisconnect(ws); } ILibWebClient_DestroyWebClientDataObject(ws->Reserved3); free(user);}/// <summary>/// Internal method dispatched from the underlying ILibAsyncServerSocket engine/// </summary>/// <param name="AsyncServerSocketModule">The ILibAsyncServerSocket token</param>/// <param name="ConnectionToken">The ILibAsyncSocket connection token</param>/// <param name="buffer">The receive buffer</param>/// <param name="p_beginPointer">buffer offset</param>/// <param name="endPointer">buffer length</param>/// <param name="OnInterrupt">Function Pointer to handle Interrupts</param>/// <param name="user">ILibWebServer_Session object</param>/// <param name="PAUSE">Flag to pause data reads on the underlying AsyncSocket engine</param>static void ILibWebServer_OnReceive(void *AsyncServerSocketModule, void *ConnectionToken,char* buffer,int *p_beginPointer, int endPointer,void (**OnInterrupt)(void *AsyncServerSocketMoudle, void *ConnectionToken, void *user), void **user, int *PAUSE){ // // Pipe the data down to our internal WebClient engine, which will do // all the HTTP processing // struct ILibWebServer_Session *ws = (struct ILibWebServer_Session*)(*user); ILibWebClient_OnData(ConnectionToken,buffer,p_beginPointer,endPointer,NULL,&(ws->Reserved3),PAUSE);}/// <summary>/// Internal method dispatched from the underlying ILibAsyncServerSocket engine, signaling an interrupt/// </summary>/// <param name="AsyncServerSocketModule">The ILibAsyncServerSocket token</param>/// <param name="ConnectionToken">The ILibAsyncSocket connection token</param>/// <param name="user">The ILibWebServer_Session object</param>static void ILibWebServer_OnInterrupt(void *AsyncServerSocketModule, void *ConnectionToken, void *user){ struct ILibWebServer_Session *session = (struct ILibWebServer_Session*)user; // This is ok, because this is MicroStackThread ILibWebClient_DestroyWebClientDataObject(session->Reserved3);}/// <summary>/// Internal method called when a request has been answered. Dispatched from Send routines/// </summary>/// <param name="session">The ILibWebServer_Session object</param>/// <returns>Flag indicating if the session was closed</returns>static int ILibWebServer_RequestAnswered(struct ILibWebServer_Session *session){ struct packetheader *hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3); struct packetheader_field_node *f; int PersistentConnection = 0; // // Reserved7 = Virtual Directory State Object // We delete this, because the request is finished, so we don't need to direct // data to this handler anymore. It needs to be recalculated next time // session->Reserved7 = NULL; // // Reqserved8 = RequestAnswered method called // If this is set, this method was already called, so we can just exit // if(session->Reserved8!=0) { return(0); } else { // // Set the flags, so if this re-enters, we don't process this again // session->Reserved8 = 1; f = hdr->FirstField; } // // Reserved6 = CloseOverrideFlag // which means the session must be closed when request is complete // if(session->Reserved6==0) { //{{{ 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 }}} // HTTP 1.0 , Check for Keep-Alive token while(f!=NULL) { if(f->FieldLength==10 && strncasecmp(f->Field,"CONNECTION",10)==0) { if(f->FieldDataLength==10 && strncasecmp(f->FieldData,"KEEP-ALIVE",10)==0) { PersistentConnection = 1; break; } } f = f->NextField; } //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} } else { // HTTP 1.1+ , Check for CLOSE token PersistentConnection = 1; while(f!=NULL) { if(f->FieldLength==10 && strncasecmp(f->Field,"CONNECTION",10)==0) { if(f->FieldDataLength==5 && strncasecmp(f->FieldData,"CLOSE",5)==0) { PersistentConnection = 0; break; } } f = f->NextField; } } //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} } if(PersistentConnection==0) { // // Ensure calling on MicroStackThread. This will just result dispatching the callback on // the microstack thread // ILibLifeTime_Add(((struct ILibWebServer_StateModule*)session->Parent)->LifeTime,session->Reserved2,0,&ILibAsyncSocket_Disconnect,NULL); } else { // // This is a persistent connection. Set a timed callback, to idle this session if necessary // ILibLifeTime_Add(((struct ILibWebServer_StateModule*)session->Parent)->LifeTime,session,HTTP_SESSION_IDLE_TIMEOUT,&ILibWebServer_IdleSink,NULL); ILibWebClient_FinishedResponse_Server(session->Reserved3); // // Since we're done with this request, resume the underlying socket, so we can continue // ILibWebClient_Resume(session->Reserved3); } return(PersistentConnection==0?ILibWebServer_SEND_RESULTED_IN_DISCONNECT:0);}/// <summary>/// Internal method dispatched from the underlying ILibAsyncServerSocket engine/// </summary>/// <param name="AsyncServerSocketModule">The ILibAsyncServerSocket token</param>/// <param name="ConnectionToken">The ILibAsyncSocket connection token</param>/// <param name="user">The ILibWebServer_Session object</param>static void ILibWebServer_OnSendOK(void *AsyncServerSocketModule,void *ConnectionToken, void *user){ struct ILibWebServer_Session *session = (struct ILibWebServer_Session*)user; int flag = 0; // // Reserved4 = RequestAnsweredFlag // if(session->Reserved4!=0) { // // This is normally called when the response was sent. But since it couldn't get through // the first time, this method gets dispatched when it did, so now we have to call it. // flag = ILibWebServer_RequestAnswered(session); } if(session->OnSendOK!=NULL && flag != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { // // Pass this event on, if everything is ok // session->OnSendOK(session); }}/// <summary>/// Constructor for ILibWebServer/// </summary>/// <param name="Chain">The Chain to add this module to</param>/// <param name="MaxConnections">The maximum number of simultaneous connections</param>/// <param name="PortNumber">The Port number to listen to (0 = Random)</param>/// <param name="OnSession">Function Pointer to dispatch on when new Sessions are established</param>/// <param name="User">User state object to pass to OnSession</param>void *ILibWebServer_Create(void *Chain, int MaxConnections, int PortNumber,ILibWebServer_Session_OnSession OnSession, void *User){ struct ILibWebServer_StateModule *RetVal = (struct ILibWebServer_StateModule*)malloc(sizeof(struct ILibWebServer_StateModule)); memset(RetVal,0,sizeof(struct ILibWebServer_StateModule)); RetVal->Destroy = &ILibWebServer_Destroy; RetVal->Chain = Chain; RetVal->OnSession = OnSession; // // Create the underling ILibAsyncServerSocket // RetVal->ServerSocket = ILibCreateAsyncServerSocketModule( Chain, MaxConnections, PortNumber, INITIAL_BUFFER_SIZE, &ILibWebServer_OnConnect, // OnConnect &ILibWebServer_OnDisconnect, // OnDisconnect &ILibWebServer_OnReceive, // OnReceive &ILibWebServer_OnInterrupt, // OnInterrupt &ILibWebServer_OnSendOK // OnSendOK ); // // Set ourselves in the User tag of the underlying ILibAsyncServerSocket // ILibAsyncServerSocket_SetTag(RetVal->ServerSocket,RetVal); RetVal->LifeTime = ILibCreateLifeTime(Chain); RetVal->User = User; ILibAddToChain(Chain,RetVal); return(RetVal);}/// <summary>/// Returns the port number that this module is listening to/// </summary>/// <param name="WebServerToken">The ILibWebServer to query</param>/// <returns>The listening port number</returns>unsigned short ILibWebServer_GetPortNumber(void *WebServerToken){ struct ILibWebServer_StateModule *WSM = (struct ILibWebServer_StateModule*) WebServerToken; return(ILibAsyncServerSocket_GetPortNumber(WSM->ServerSocket));}/// <summary>/// Send a response on a Session/// </summary>/// <param name="session">The ILibWebServer_Session to send the response on</param>/// <param name="packet">The packet to respond with</param>/// <returns>Flag indicating send status</returns>int ILibWebServer_Send(struct ILibWebServer_Session *session, struct packetheader *packet){ char *buffer; int bufferSize; int RetVal = 0; if(session==NULL) { ILibDestructPacket(packet); return(ILibWebServer_INVALID_SESSION); } session->Reserved4=1; bufferSize = ILibGetRawPacket(packet,&buffer); RetVal = ILibAsyncServerSocket_Send(session->Reserved1,session->Reserved2,buffer,bufferSize,0); if(RetVal==0) { // Completed Send RetVal = ILibWebServer_RequestAnswered(session); } ILibDestructPacket(packet); return(RetVal);}/// <summary>/// Send a response on a Session, directly specifying the buffers to send/// </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 length of the buffer</param>/// <param name="userFree">The ownership flag of the buffer</param>/// <param name="done">Flag indicating if this is everything</param>/// <returns>Send Status</returns>int ILibWebServer_Send_Raw(struct ILibWebServer_Session *session, char *buffer, int bufferSize, int userFree, int done){ int RetVal=0; if(session==NULL) { if(userFree==ILibAsyncSocket_MemoryOwnership_CHAIN) {free(buffer);} return(ILibWebServer_INVALID_SESSION); } session->Reserved4 = done; RetVal = ILibAsyncServerSocket_Send(session->Reserved1,session->Reserved2,buffer,bufferSize,userFree); if(RetVal==0 && done!=0) { // Completed Send RetVal = ILibWebServer_RequestAnswered(session); } return(RetVal);}/// <summary>/// Streams the HTTP header response on a session, directly specifying the buffer/// </summary>/// <para>/// DO NOT specify Content-Length or Transfer-Encoding./// </para>/// <param name="session">The ILibWebServer_Session to send the response on</param>/// <param name="StatusCode">The HTTP status code, eg: 200</param>/// <param name="StatusData">The HTTP status data, eg: OK</param>/// <param name="ResponseHeaders">The ownership flag of the buffer</param>/// <param name="ResponseHeaders_FREE">Flag indicating if this is everything</param>/// <returns>Send Status</returns>int ILibWebServer_StreamHeader_Raw(struct ILibWebServer_Session *session, int StatusCode,char *StatusData,char *ResponseHeaders, int ResponseHeaders_FREE){ struct packetheader *hdr; char *buffer; int bufferLength; int RetVal; struct parser_result *pr,*pr2; struct parser_result_field *prf; int len; char *temp; int tempLength; if(session==NULL) { if(ResponseHeaders_FREE==ILibAsyncSocket_MemoryOwnership_CHAIN) {free(ResponseHeaders);} return(ILibWebServer_INVALID_SESSION); } hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3); // // Allocate the response header buffer // ToDo: May want to make the response version dynamic or at least #define // buffer = (char*)malloc(20+strlen(StatusData)); bufferLength = sprintf(buffer,"HTTP/%s %d %s",HTTPVERSION,StatusCode,StatusData); // // Send the first portion of the headers across // RetVal = ILibWebServer_Send_Raw(session,buffer,bufferLength,0,0); if(RetVal != ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR && RetVal != ILibWebServer_SEND_RESULTED_IN_DISCONNECT) { // // The Send went through
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -