| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- /*
- * Copyright (c) 2014, Oculus VR, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
- #include "NativeFeatureIncludes.h"
- #if _RAKNET_SUPPORT_HTTPConnection2==1 && _RAKNET_SUPPORT_TCPInterface==1
- #include "HTTPConnection2.h"
- #include "TCPInterface.h"
- using namespace RakNet;
- STATIC_FACTORY_DEFINITIONS(HTTPConnection2,HTTPConnection2);
- HTTPConnection2::HTTPConnection2()
- {
- }
- HTTPConnection2::~HTTPConnection2()
- {
- }
- bool HTTPConnection2::TransmitRequest(const char* stringToTransmit, const char* host, unsigned short port, bool useSSL, int ipVersion, SystemAddress useAddress, void *userData)
- {
- Request *request = RakNet::OP_NEW<Request>(_FILE_AND_LINE_);
- request->host=host;
- request->chunked = false;
- if (useAddress!=UNASSIGNED_SYSTEM_ADDRESS)
- {
- request->hostEstimatedAddress=useAddress;
- if (IsConnected(useAddress)==false)
- {
- RakNet::OP_DELETE(request, _FILE_AND_LINE_);
- return false;
- }
- }
- else
- {
- if (request->hostEstimatedAddress.FromString(host, '|', ipVersion)==false)
- {
- RakNet::OP_DELETE(request, _FILE_AND_LINE_);
- return false;
- }
- }
- request->hostEstimatedAddress.SetPortHostOrder(port);
- request->port=port;
- request->stringToTransmit=stringToTransmit;
- request->contentLength=-1;
- request->contentOffset=0;
- request->useSSL=useSSL;
- request->ipVersion=ipVersion;
- request->userData=userData;
- if (IsConnected(request->hostEstimatedAddress))
- {
- sentRequestsMutex.Lock();
- if (sentRequests.Size()==0)
- {
- request->hostCompletedAddress=request->hostEstimatedAddress;
- sentRequests.Push(request, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- SendRequest(request);
- }
- else
- {
- // Request pending, push it
- pendingRequestsMutex.Lock();
- pendingRequests.Push(request, _FILE_AND_LINE_);
- pendingRequestsMutex.Unlock();
- sentRequestsMutex.Unlock();
- }
- }
- else
- {
- pendingRequestsMutex.Lock();
- pendingRequests.Push(request, _FILE_AND_LINE_);
- pendingRequestsMutex.Unlock();
- if (ipVersion!=6)
- {
- tcpInterface->Connect(host, port, false, AF_INET);
- }
- else
- {
- #if RAKNET_SUPPORT_IPV6
- tcpInterface->Connect(host, port, false, AF_INET6);
- #else
- RakAssert("HTTPConnection2::TransmitRequest needs define RAKNET_SUPPORT_IPV6" && 0);
- #endif
- }
- }
- return true;
- }
- bool HTTPConnection2::GetResponse( RakString &stringTransmitted, RakString &hostTransmitted, RakString &responseReceived, SystemAddress &hostReceived, int &contentOffset )
- {
- void *userData;
- return GetResponse(stringTransmitted, hostTransmitted, responseReceived, hostReceived, contentOffset, &userData);
- }
- bool HTTPConnection2::GetResponse( RakString &stringTransmitted, RakString &hostTransmitted, RakString &responseReceived, SystemAddress &hostReceived, int &contentOffset, void **userData )
- {
- completedRequestsMutex.Lock();
- if (completedRequests.Size()>0)
- {
- Request *completedRequest = completedRequests[0];
- completedRequests.RemoveAtIndexFast(0);
- completedRequestsMutex.Unlock();
- responseReceived = completedRequest->stringReceived;
- hostReceived = completedRequest->hostCompletedAddress;
- stringTransmitted = completedRequest->stringToTransmit;
- hostTransmitted = completedRequest->host;
- contentOffset = completedRequest->contentOffset;
- *userData = completedRequest->userData;
- RakNet::OP_DELETE(completedRequest, _FILE_AND_LINE_);
- return true;
- }
- else
- {
- completedRequestsMutex.Unlock();
- }
- return false;
- }
- bool HTTPConnection2::IsBusy(void) const
- {
- return pendingRequests.Size()>0 || sentRequests.Size()>0;
- }
- bool HTTPConnection2::HasResponse(void) const
- {
- return completedRequests.Size()>0;
- }
- int ReadChunkSize( char *txtStart, char **txtEnd )
- {
- // char lengthStr[32];
- // memset(lengthStr, 0, 32);
- // memcpy(lengthStr, txtStart, txtEnd - txtStart);
- return strtoul(txtStart, txtEnd,16);
- // return atoi(lengthStr);
- }
- void ReadChunkBlock( size_t ¤tChunkSize, size_t &bytesReadSoFar, char *txtIn, RakString &txtOut)
- {
- size_t bytesToRead;
- size_t sLen;
-
- do
- {
- bytesToRead = currentChunkSize - bytesReadSoFar;
- sLen = strlen(txtIn);
- if (sLen < bytesToRead)
- bytesToRead = sLen;
- txtOut.AppendBytes(txtIn, bytesToRead);
- txtIn += bytesToRead;
- bytesReadSoFar += bytesToRead;
- if (*txtIn == 0)
- {
- // currentChunkSize=0;
- return;
- }
- // char *newLine = strstr(txtIn, "\r\n");
- if (txtIn[0] && txtIn[0]=='\r' && txtIn[1] && txtIn[1]=='\n' )
- txtIn += 2; // Newline
- char *newLine;
- currentChunkSize = ReadChunkSize(txtIn, &newLine);
- RakAssert(currentChunkSize < 50000); // Sanity check
- if (currentChunkSize == 0)
- return;
- if (newLine == 0)
- return;
- bytesReadSoFar=0;
- txtIn = newLine + 2;
- } while (txtIn);
- }
- PluginReceiveResult HTTPConnection2::OnReceive(Packet *packet)
- {
- unsigned int i;
- bool locked=true;
- sentRequestsMutex.Lock();
- for (i=0; i < sentRequests.Size(); i++)
- {
- Request *sentRequest = sentRequests[i];
- if (sentRequest->hostCompletedAddress==packet->systemAddress)
- {
- sentRequests.RemoveAtIndexFast(i);
- locked=false;
- sentRequestsMutex.Unlock();
- /*
- static FILE * pFile = 0;
- if (pFile==0)
- {
- long lSize;
- char * buffer;
- size_t result;
- pFile = fopen ( "string_received.txt" , "rb" );
- if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
- // obtain file size:
- fseek (pFile , 0 , SEEK_END);
- lSize = ftell (pFile);
- rewind (pFile);
- // allocate memory to contain the whole file:
- buffer = (char*) malloc (sizeof(char)*lSize);
- if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
- // copy the file into the buffer:
- result = fread (buffer,1,lSize,pFile);
- if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
- packet->data=(unsigned char*) buffer;
- packet->length=lSize;
- }
- */
- const char *isFirstChunk = strstr((char*) packet->data, "Transfer-Encoding: chunked");
- if (isFirstChunk)
- {
- //printf((char*) packet->data);
- locked=false;
- sentRequestsMutex.Unlock();
- sentRequest->chunked = true;
- char *chunkStrStart = strstr((char*) packet->data, "\r\n\r\n");
- RakAssert(chunkStrStart);
- chunkStrStart += 4; // strlen("\r\n\r\n");
- char *body_header; // = strstr(chunkStrStart, "\r\n");
- sentRequest->thisChunkSize = ReadChunkSize(chunkStrStart, &body_header);
- sentRequest->bytesReadForThisChunk = 0;
- sentRequest->contentOffset = 0;
- if (sentRequest->thisChunkSize == 0)
- {
- // Done
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequest, _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- // If there is another command waiting for this server, send it
- SendPendingRequestToConnectedSystem(packet->systemAddress);
- }
- else
- {
- // char *offset = strstr((char*) packet->data+1, "2000");
- body_header+=2;
- ReadChunkBlock(sentRequest->thisChunkSize, sentRequest->bytesReadForThisChunk, body_header, sentRequest->stringReceived);
- if (sentRequest->thisChunkSize==0)
- {
- // Done
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequest, _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- // If there is another command waiting for this server, send it
- SendPendingRequestToConnectedSystem(packet->systemAddress);
- }
- else
- {
- // Not done
- sentRequestsMutex.Lock();
- sentRequests.Push(sentRequest, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- }
- }
- }
- else if (sentRequest->chunked)
- {
- ReadChunkBlock(sentRequest->thisChunkSize, sentRequest->bytesReadForThisChunk, (char*) packet->data, sentRequest->stringReceived);
- if (sentRequest->thisChunkSize==0)
- {
- // Done
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequest, _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- // If there is another command waiting for this server, send it
- SendPendingRequestToConnectedSystem(packet->systemAddress);
- }
- else
- {
- // Not done
- sentRequestsMutex.Lock();
- sentRequests.Push(sentRequest, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- }
- }
- else
- {
- sentRequest->stringReceived+=packet->data;
- if (sentRequest->contentLength==-1)
- {
- const char *length_header = strstr(sentRequest->stringReceived.C_String(), "Content-Length: ");
- if(length_header)
- {
- length_header += 16; // strlen("Content-Length: ");
- unsigned int clLength;
- for (clLength=0; length_header[clLength] && length_header[clLength] >= '0' && length_header[clLength] <= '9'; clLength++)
- ;
- if (clLength>0 && (length_header[clLength]=='\r' || length_header[clLength]=='\n'))
- {
- sentRequest->contentLength = RakString::ReadIntFromSubstring(length_header, 0, clLength);
- }
- }
- }
- // If we know the content length, find \r\n\r\n
- if (sentRequest->contentLength != -1)
- {
- if (sentRequest->contentLength > 0)
- {
- const char *body_header = strstr(sentRequest->stringReceived.C_String(), "\r\n\r\n");
- if (body_header)
- {
- body_header += 4; // strlen("\r\n\r\n");
- size_t slen = strlen(body_header);
- //RakAssert(slen <= (size_t) sentRequest->contentLength);
- if (slen >= (size_t) sentRequest->contentLength)
- {
- sentRequest->contentOffset = body_header - sentRequest->stringReceived.C_String();
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequest, _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- // If there is another command waiting for this server, send it
- SendPendingRequestToConnectedSystem(packet->systemAddress);
- }
- else
- {
- sentRequestsMutex.Lock();
- sentRequests.Push(sentRequest, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- }
- }
- else
- {
- sentRequestsMutex.Lock();
- sentRequests.Push(sentRequest, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- }
- }
- else
- {
- sentRequest->contentOffset=-1;
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequest, _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- // If there is another command waiting for this server, send it
- SendPendingRequestToConnectedSystem(packet->systemAddress);
- }
- }
- else
- {
- const char *firstNewlineSet = strstr(sentRequest->stringReceived.C_String(), "\r\n\r\n");
- if (firstNewlineSet!=0)
- {
- int offset = firstNewlineSet - sentRequest->stringReceived.C_String();
- if (sentRequest->stringReceived.C_String()[offset+4]==0)
- sentRequest->contentOffset=-1;
- else
- sentRequest->contentOffset=offset+4;
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequest, _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- // If there is another command waiting for this server, send it
- SendPendingRequestToConnectedSystem(packet->systemAddress);
- }
- else
- {
- sentRequestsMutex.Lock();
- sentRequests.Push(sentRequest, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- }
- }
- }
-
- break;
- }
- }
- if (locked==true)
- sentRequestsMutex.Unlock();
- return RR_CONTINUE_PROCESSING;
- }
- void HTTPConnection2::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
- {
- (void) rakNetGUID;
- (void) isIncoming; // unknown
- SendPendingRequestToConnectedSystem(systemAddress);
- }
- void HTTPConnection2::SendPendingRequestToConnectedSystem(SystemAddress sa)
- {
- if (sa==UNASSIGNED_SYSTEM_ADDRESS)
- return;
- unsigned int requestsSent=0;
- // Search through requests to find a match for this instance of TCPInterface and SystemAddress
- unsigned int i;
- i=0;
- pendingRequestsMutex.Lock();
- while (i < pendingRequests.Size())
- {
- Request *request = pendingRequests[i];
- if (request->hostEstimatedAddress==sa)
- {
- pendingRequests.RemoveAtIndex(i);
- // Send this request
- request->hostCompletedAddress=sa;
- sentRequestsMutex.Lock();
- sentRequests.Push(request, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- pendingRequestsMutex.Unlock();
- #if OPEN_SSL_CLIENT_SUPPORT==1
- if (request->useSSL)
- tcpInterface->StartSSLClient(sa);
- #endif
- SendRequest(request);
- requestsSent++;
- pendingRequestsMutex.Lock();
- break;
- }
- else
- {
- i++;
- }
- }
- pendingRequestsMutex.Unlock();
- if (requestsSent==0)
- {
- pendingRequestsMutex.Lock();
- if (pendingRequests.Size() > 0)
- {
- // Just assign
- Request *request = pendingRequests[0];
- pendingRequests.RemoveAtIndex(0);
- request->hostCompletedAddress=sa;
- sentRequestsMutex.Lock();
- sentRequests.Push(request, _FILE_AND_LINE_);
- sentRequestsMutex.Unlock();
- pendingRequestsMutex.Unlock();
- // Send
- #if OPEN_SSL_CLIENT_SUPPORT==1
- if (request->useSSL)
- tcpInterface->StartSSLClient(sa);
- #endif
- SendRequest(request);
- }
- else
- {
- pendingRequestsMutex.Unlock();
- }
- }
- }
- void HTTPConnection2::RemovePendingRequest(SystemAddress sa)
- {
- unsigned int i;
- i=0;
- pendingRequestsMutex.Lock();
- for (i=0; i < pendingRequests.Size(); i++)
- {
- Request *request = pendingRequests[i];
- if (request->hostEstimatedAddress==sa)
- {
- pendingRequests.RemoveAtIndex(i);
- RakNet::OP_DELETE(request, _FILE_AND_LINE_);
- }
- else
- i++;
- }
- pendingRequestsMutex.Unlock();
- }
- void HTTPConnection2::SendNextPendingRequest(void)
- {
- // Send a pending request
- pendingRequestsMutex.Lock();
- if (pendingRequests.Size()>0)
- {
- Request *pendingRequest = pendingRequests.Peek();
- pendingRequestsMutex.Unlock();
- if (pendingRequest->ipVersion!=6)
- {
- tcpInterface->Connect(pendingRequest->host.C_String(), pendingRequest->port, false, AF_INET);
- }
- else
- {
- #if RAKNET_SUPPORT_IPV6
- tcpInterface->Connect(pendingRequest->host.C_String(), pendingRequest->port, false, AF_INET6);
- #else
- RakAssert("HTTPConnection2::TransmitRequest needs define RAKNET_SUPPORT_IPV6" && 0);
- #endif
- }
- }
- else
- {
- pendingRequestsMutex.Unlock();
- }
- }
- void HTTPConnection2::OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason)
- {
- (void) failedConnectionAttemptReason;
- if (packet->systemAddress==UNASSIGNED_SYSTEM_ADDRESS)
- return;
- RemovePendingRequest(packet->systemAddress);
- SendNextPendingRequest();
- }
- void HTTPConnection2::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
- {
- (void) lostConnectionReason;
- (void) rakNetGUID;
- if (systemAddress==UNASSIGNED_SYSTEM_ADDRESS)
- return;
- // Update sent requests to completed requests
- unsigned int i;
- i=0;
- sentRequestsMutex.Lock();
- while (i < sentRequests.Size())
- {
- if (sentRequests[i]->hostCompletedAddress==systemAddress)
- {
- Request *sentRequest = sentRequests[i];
- if (sentRequest->chunked==false && sentRequest->stringReceived.IsEmpty()==false)
- {
- if (strstr(sentRequest->stringReceived.C_String(), "Content-Length: "))
- {
- char *body_header = strstr((char*) sentRequest->stringReceived.C_String(), "\r\n\r\n");
- if (body_header)
- {
- body_header += 4; // strlen("\r\n\r\n");
- sentRequest->contentOffset = body_header - sentRequest->stringReceived.C_String();
- }
- else
- {
- sentRequest->contentOffset = 0;
- }
- }
- else
- {
- sentRequest->contentOffset = 0;
- }
- }
-
- completedRequestsMutex.Lock();
- completedRequests.Push(sentRequests[i], _FILE_AND_LINE_);
- completedRequestsMutex.Unlock();
- sentRequests.RemoveAtIndexFast(i);
- }
- else
- {
- i++;
- }
- }
- sentRequestsMutex.Unlock();
- SendNextPendingRequest();
- }
- bool HTTPConnection2::IsConnected(SystemAddress sa)
- {
- SystemAddress remoteSystems[64];
- unsigned short numberOfSystems=64;
- tcpInterface->GetConnectionList(remoteSystems, &numberOfSystems);
- for (unsigned int i=0; i < numberOfSystems; i++)
- {
- if (remoteSystems[i]==sa)
- {
- return true;
- }
- }
- return false;
- }
- void HTTPConnection2::SendRequest(Request *request)
- {
- tcpInterface->Send(request->stringToTransmit.C_String(), (unsigned int) request->stringToTransmit.GetLength(), request->hostCompletedAddress, false);
- }
- #endif // #if _RAKNET_SUPPORT_HTTPConnection2==1 && _RAKNET_SUPPORT_TCPInterface==1
|