📄 ilibwebclient.c
字号:
} if(wcdo->BytesLeft==0) { // // We already have the complete Response Packet // if(wr->OnResponse!=NULL) { wr->OnResponse( socketModule, 0, wcdo->header, NULL, &zero, 0, -1, wr->user1, wr->user2, &(wcdo->PAUSE)); } *p_beginPointer = *p_beginPointer + i + 4; ILibWebClient_FinishedResponse(socketModule,wcdo); } else { // // There is still data we need to read. Lets see if any of the // body arrived yet // if(wcdo->Chunked==0) { // // This isn't chunked, so we can process normally // if(wcdo->BytesLeft!=-1 && (endPointer-(*p_beginPointer)) - (i+4) >= wcdo->BytesLeft) { // // We have the entire body now, so we have the entire packet // if(wr->OnResponse!=NULL) { wr->OnResponse( socketModule, 0, wcdo->header, buffer+i+4, &zero, wcdo->BytesLeft, -1, wr->user1, wr->user2, &(wcdo->PAUSE)); } *p_beginPointer = *p_beginPointer + i + 4 + (zero==0?wcdo->BytesLeft:zero); ILibWebClient_FinishedResponse(socketModule,wcdo); } else { // // We read some of the body, but not all of it yet // if(wr->OnResponse!=NULL) { wr->OnResponse( socketModule, 0, wcdo->header, buffer+i+4, &zero, (endPointer - (*p_beginPointer) - (i+4)), 0, wr->user1, wr->user2, &(wcdo->PAUSE)); } wcdo->HeaderLength = 0; *p_beginPointer = i+4+zero; wcdo->BytesLeft -= zero; // // We are consuming the header portion of the buffer // so we need to copy it out, so we can recycle the buffer // for the body // tph = ILibClonePacket(wcdo->header); ILibDestructPacket(wcdo->header); wcdo->header = tph; } }//{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} else { // // This packet is chunk encoded, so we need to run it // through our Chunk Processor // ILibWebClient_ProcessChunk(socketModule,wcdo,buffer+i+4,&zero,(endPointer - (*p_beginPointer) - (i+4))); *p_beginPointer = i+4+zero; tph = ILibClonePacket(wcdo->header); ILibDestructPacket(wcdo->header); wcdo->header = tph; }//{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} } } else { // // ToDo: There was an error parsing the headers. What should we do about it? // Right now, we don't care // } break; } ++i; } } } else { // // We already processed the headers, so we are only expecting the body now // if(wcdo->Chunked==0) { // // This isn't chunk encoded // if(wcdo->WaitForClose==0) { // // This is to determine if we have everything // Fini = ((endPointer - (*p_beginPointer))>=wcdo->BytesLeft)?-1:0; } else { // // We need to read until the socket closes // Fini = 0; } if(wr->OnResponse!=NULL) { wr->OnResponse( socketModule, 0, wcdo->header, buffer, p_beginPointer, wcdo->WaitForClose==0?(((endPointer - (*p_beginPointer))>=wcdo->BytesLeft)?wcdo->BytesLeft:(endPointer - (*p_beginPointer))):(endPointer-(*p_beginPointer)), Fini, wr->user1, wr->user2, &(wcdo->PAUSE)); } if(ILibAsyncSocket_IsFree(socketModule)==0) { if(wcdo->WaitForClose==0) { // // Decrement our counters // wcdo->BytesLeft -= *p_beginPointer; if(Fini!=0) { // // We finished processing this, so signal it // *p_beginPointer = *p_beginPointer + wcdo->BytesLeft; ILibWebClient_FinishedResponse(socketModule,wcdo); } } } }//{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} else { // // This is chunk encoded, so run it through our Chunk Processor // ILibWebClient_ProcessChunk(socketModule,wcdo,buffer,p_beginPointer,endPointer); }//{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} } if(ILibAsyncSocket_IsFree(socketModule)==0) { // // If the user said to pause this connection, do so // *PAUSE = wcdo->PAUSE; }}/// <summary>/// Internal method dispatched by the LifeTimeMonitor, to retry refused connections/// </summary>/// <para>/// This module does an exponential backoff, when retrying connections. The number/// of retries is determined by the value of HTTP_CONNECT_RETRY_COUNT/// </para>/// <param name="object">The associated WebClientDataObject</param>static void ILibWebClient_RetrySink(void *object){ char key[22]; int keyLength; struct ILibWebClientDataObject *wcdo = (struct ILibWebClientDataObject*)object; wcdo->ExponentialBackoff = wcdo->ExponentialBackoff==0?1:wcdo->ExponentialBackoff * 2; SEM_TRACK(WebClient_TrackLock("ILibWebClient_RetrySink",1,wcm);) if(wcdo->ExponentialBackoff==(int)pow((double)2,(double)HTTP_CONNECT_RETRY_COUNT)) { // // Retried enough times, give up // keyLength = sprintf(key,"%s:%d",inet_ntoa(wcdo->remote.sin_addr),(int)ntohs(wcdo->remote.sin_port)); MEMCHECK(assert(keyLength<=21);) ILibDeleteEntry(wcdo->Parent->DataTable,key,keyLength); ILibDeleteEntry(wcdo->Parent->idleTable,key,keyLength); SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_RetrySink",2,wcm);) ILibWebClient_DestroyWebClientDataObject(wcdo); return; } else { // // Lets retry again // ILibQueue_EnQueue(wcdo->Parent->backlogQueue,wcdo); } SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_RetrySink",3,wcm);)}/// <summary>/// Internal method dispatched by the OnConnect event of the underlying ILibAsyncSocket/// </summary>/// <param name="socketModule">The underlying ILibAsyncSocket</param>/// <param name="Connected">Flag indicating connect status: Nonzero indicates success</param>/// <param name="user">Associated WebClientDataObject</param>static void ILibWebClient_OnConnect(void* socketModule, int Connected, void *user){ struct ILibWebClientDataObject *wcdo = (struct ILibWebClientDataObject*)user; struct ILibWebRequest *r; int i; wcdo->SOCK = socketModule; wcdo->InitialRequestAnswered=0; wcdo->DisconnectSent=0; if(Connected!=0 && wcdo->DisconnectSent==0) { //Success: Send First Request wcdo->LocalIP = ILibAsyncSocket_GetLocalInterface(socketModule); wcdo->ExponentialBackoff=1; SEM_TRACK(WebClient_TrackLock("ILibWebClient_OnConnect",1,wcdo->Parent);) r = ILibQueue_PeekQueue(wcdo->RequestQueue); SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_OnConnect",2,wcdo->Parent);) for(i=0;i<r->NumberOfBuffers;++i) { ILibAsyncSocket_Send(socketModule,r->Buffer[i],r->BufferLength[i],-1); } } else { // // The connection failed, so lets set a timed callback, and try again // if(wcdo->DisconnectSent==0) { wcdo->Closing=2; //This is required, so we don't notify the user yet ILibAsyncSocket_Disconnect(socketModule); wcdo->Closing=0; //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} wcdo->PipelineFlag = PIPELINE_UNKNOWN; //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} } ILibLifeTime_Add(wcdo->Parent->timer,wcdo,wcdo->ExponentialBackoff,&ILibWebClient_RetrySink,NULL); }}/// <summary>/// Internal method dispatched by the OnDisconnect event of the underlying ILibAsyncSocket/// </summary>/// <param name="socketModule">The underlying ILibAsyncSocket</param>/// <param name="user">The associated WebClientDataObject</param>static void ILibWebClient_OnDisconnect(void* socketModule, void *user){ struct packetheader *h; struct ILibWebClientDataObject *wcdo = (struct ILibWebClientDataObject*)user; struct ILibWebRequest *wr; char *buffer; int BeginPointer,EndPointer; if(wcdo==NULL) {return;} if(wcdo->DisconnectSent!=0) { // // We probably closed the socket on purpose, and don't want to tell // anyone about it yet // return; } else if(ILibQueue_PeekQueue(wcdo->RequestQueue)!=NULL) { // // There are still pending requests, so we probably already // send the disconnect event up // wcdo->DisconnectSent = 1; } //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} if(wcdo->Closing==0) { if(ILibQueue_PeekQueue(wcdo->RequestQueue)!=NULL) { // // If there are still pending requests, than obviously this server // doesn't do persistent connections // wcdo->PipelineFlag = PIPELINE_NO; } } //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} if(wcdo->WaitForClose!=0) { // // Since we had to read until the socket closes, we finally have // all the data we need // ILibAsyncSocket_GetBuffer(socketModule,&buffer,&BeginPointer,&EndPointer); SEM_TRACK(WebClient_TrackLock("ILibWebClient_OnDisconnect",1,wcdo->Parent);) wr = ILibQueue_DeQueue(wcdo->RequestQueue); SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_OnDisconnect",2,wcdo->Parent);) wcdo->InitialRequestAnswered=1; //{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}} wcdo->PipelineFlag = PIPELINE_NO; //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} wcdo->FinHeader=0; h = wcdo->header; wcdo->header = NULL; if(wr!=NULL && wr->OnResponse!=NULL) { wr->OnResponse( socketModule, 0, h, buffer, &BeginPointer, EndPointer, -1, wr->user1, wr->user2, &(wcdo->PAUSE)); //ILibWebClient_FinishedResponse(socketModule,wcdo); } if(wcdo->DisconnectSent==1) { wcdo->DisconnectSent=0; } ILibWebClient_DestroyWebRequest(wr); if(h!=NULL) { ILibDestructPacket(h); } } if(wcdo->Closing!=0){return;} SEM_TRACK(WebClient_TrackLock("ILibWebClient_OnDisconnect",3,wcdo->Parent);) wr = ILibQueue_PeekQueue(wcdo->RequestQueue); SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_OnDisconnect",4,wcdo->Parent);) if(wr!=NULL) { // Still Requests to be made if(wcdo->InitialRequestAnswered==0) { //Error wr->OnResponse( socketModule, 0, NULL, NULL, NULL, 0, -1, wr->user1, wr->user2, &(wcdo->PAUSE)); ILibWebClient_FinishedResponse(socketModule,wcdo); SEM_TRACK(WebClient_TrackLock("ILibWebClient_OnDisconnect",5,wcdo->Parent);) wr = ILibQueue_PeekQueue(wcdo->RequestQueue); SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_OnDisconnect",6,wcdo->Parent);) if(wr==NULL){return;} } // Make Another Connection and Continue wcdo->Closing = 0; ILibQueue_EnQueue(wcdo->Parent->backlogQueue,wcdo); }}/// <summary>/// Internal method dispatched by the OnSendOK event of the underlying ILibAsyncSocket/// </summary>/// <param name="socketModule">The underlying ILibAsyncSocket</param>/// <param name="user">The associated WebClientDataObject</param>static void ILibWebClient_OnSendOK(void *socketModule, void *user){}/// <summary>/// Chain PreSelect handler/// </summary>/// <param name="WebClientModule">The WebClient token</param>/// <param name="readset"></param>/// <param name="writeset"></param>/// <param name="errorset"></param>/// <param name="blocktime"></param>static void ILibWebClient_PreProcess(void* WebClientModule,fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime){ struct ILibWebClientManager *wcm = (struct ILibWebClientManager*)WebClientModule; struct ILibWebClientDataObject *wcdo; int i; int OK=0; // // Try and satisfy as many things as we can. If we have resources // grab a socket and go // SEM_TRACK(WebClient_TrackLock("ILibWebClient_PreProcess",1,wcm);) while(OK==0 && ILibQueue_IsEmpty(wcm->backlogQueue)==0) { OK=1; for(i=0;i<wcm->socksLength;++i) { if(ILibAsyncSocket_IsFree(wcm->socks[i])!=0) { OK=0; wcdo = ILibQueue_DeQueue(wcm->backlogQueue); if(wcdo!=NULL) { wcdo->Closing = 0; ILibAsyncSocket_ConnectTo( wcm->socks[i], INADDR_ANY, wcdo->remote.sin_addr.s_addr, (int)ntohs(wcdo->remote.sin_port), NULL, wcdo); } } if(ILibQueue_IsEmpty(wcm->backlogQueue)!=0) {break;} } } SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_PreProcess",2,wcm);)}/// <summary>/// Internal method dispatched by either ILibWebServer or ILibWebClient, to recheck the headers/// </summary>/// <para>/// In certain cases, when the underlying buffer has been reallocated, the pointers in the /// header structure will be invalid./// </para>/// <param name="token">The sender</param>/// <param name="user">The WCDO object</param>/// <param name="offSet">The offSet to the new buffer location</param>void ILibWebClient_OnBufferReAllocate(void *token, void *user, ptrdiff_t offSet){ struct packetheader_field_node *n; struct ILibWebClientDataObject *wcdo = (struct ILibWebClientDataObject*)user; if(wcdo!=NULL && wcdo->header!=NULL) { // // Sometimes, the header was copied, in which case this realloc doesn't affect us // if(wcdo->header->ClonedPacket==0) { // // Sometimes the user instantiated the string, so again // this may not concern us // if(wcdo->header->UserAllocStrings==0) { if(wcdo->header->StatusCode==-1) { // Request Packet wcdo->header->Directive += offSet; wcdo->header->DirectiveObj += offSet; } else { // Response Packet wcdo->header->StatusData += offSet; } } // // Sometimes the user instantiated the string, so again // this may not concern us // if(wcdo->header->UserAllocVersion==0) { wcdo->header->Version += offSet; } n = wcdo->header->FirstField; while(n!=NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -