• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

HTTPConnection.cpp

Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 #include "NativeFeatureIncludes.h"
00019 #if _RAKNET_SUPPORT_HTTPConnection==1
00020 
00021 #include "TCPInterface.h"
00022 #include "HTTPConnection.h"
00023 #include "RakSleep.h"
00024 #include "RakString.h"
00025 #include "RakAssert.h"
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 
00031 using namespace RakNet;
00032 
00033 HTTPConnection::HTTPConnection() : connectionState(CS_NONE)
00034 {
00035         tcp=0;
00036 }
00037 
00038 void HTTPConnection::Init(TCPInterface* _tcp, const char *_host, unsigned short _port)
00039 {
00040         tcp=_tcp;
00041         host=_host;
00042         port=_port;
00043 }
00044 
00045 void HTTPConnection::Post(const char *remote_path, const char *data, const char *_contentType)
00046 {
00047         OutgoingPost op;
00048         op.contentType=_contentType;
00049         op.data=data;
00050         op.remotePath=remote_path;
00051         outgoingPosts.Push(op, __FILE__, __LINE__ );
00052         //printf("Adding outgoing post\n");
00053 }
00054 
00055 bool HTTPConnection::HasBadResponse(int *code, RakNet::RakString *data)
00056 {
00057     if(badResponses.IsEmpty())
00058         return false;
00059 
00060         if (code)
00061                 *code = badResponses.Peek().code;
00062         if (data)
00063                 *data = badResponses.Pop().data;
00064    return true;
00065 }
00066 void HTTPConnection::CloseConnection()
00067 {
00068         connectionState=CS_DISCONNECTING;
00069 }
00070 void HTTPConnection::Update(void)
00071 {
00072         SystemAddress sa;
00073         sa = tcp->HasCompletedConnectionAttempt();
00074         while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
00075         {
00076 //              printf("Connected\n");
00077                 connectionState=CS_CONNECTED;
00078                 server=sa;
00079                 sa = tcp->HasCompletedConnectionAttempt();
00080         }
00081 
00082         sa = tcp->HasFailedConnectionAttempt();
00083         while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
00084         {
00085                 //printf("Failed connected\n");
00086                 CloseConnection();
00087                 sa = tcp->HasFailedConnectionAttempt();
00088         }
00089 
00090         sa = tcp->HasLostConnection();
00091         while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
00092         {
00093                 //printf("Lost connection\n");
00094                 CloseConnection();
00095                 sa = tcp->HasLostConnection();
00096         }
00097 
00098 
00099         switch (connectionState)
00100         {
00101         case CS_NONE:
00102                 {
00103                         if (outgoingPosts.IsEmpty())
00104                                 return;
00105 
00106                         //printf("Connecting\n");
00107                         server = tcp->Connect(host, port, false);
00108                         connectionState = CS_CONNECTING;
00109                 }
00110                 break;
00111         case CS_DISCONNECTING:
00112                 {
00113                         if (tcp->ReceiveHasPackets()==false)
00114                         {
00115                                 if (incomingData.IsEmpty()==false)
00116                                 {
00117                                         results.Push(incomingData, __FILE__, __LINE__ );
00118                                 }
00119                                 incomingData.Clear();
00120                                 tcp->CloseConnection(server);
00121                                 connectionState=CS_NONE;
00122                         }
00123                 }
00124                 break;
00125         case CS_CONNECTING:
00126                 {
00127                 }
00128                 break;
00129         case CS_CONNECTED:
00130                 {
00131                         //printf("Connected\n");
00132                         if (outgoingPosts.IsEmpty())
00133                         {
00134                                 //printf("Closed connection (nothing to do)\n");
00135                                 CloseConnection();
00136                                 return;
00137                         }
00138 
00139 #if defined(OPEN_SSL_CLIENT_SUPPORT)
00140                         tcp->StartSSLClient(server);
00141 #endif
00142 
00143                         //printf("Sending request\n");
00144                         currentProcessingRequest = outgoingPosts.Pop();
00145                         RakString request("POST %s HTTP/1.0\r\n"
00146                                 "Host: %s:%i\r\n"
00147                                 "Content-Type: %s\r\n"
00148                                 "Content-Length: %u\r\n"
00149                                 "\r\n"
00150                                 "%s",
00151                                 currentProcessingRequest.remotePath.C_String(),
00152                                 host.C_String(),
00153                                 port,
00154                                 currentProcessingRequest.contentType.C_String(),
00155                                 (unsigned) currentProcessingRequest.data.GetLength(),
00156                                 currentProcessingRequest.data.C_String());
00157         //              request.URLEncode();
00158                         tcp->Send(request.C_String(), (unsigned int) request.GetLength(), server,false);
00159                         connectionState=CS_PROCESSING;
00160                 }
00161                 break;
00162         case CS_PROCESSING:
00163                 {
00164                 }
00165         }
00166 
00167 //      if (connectionState==CS_PROCESSING && currentProcessingRequest.data.IsEmpty()==false)
00168 //              outgoingPosts.PushAtHead(currentProcessingRequest);
00169 }
00170 bool HTTPConnection::HasRead(void) const
00171 {
00172         return results.IsEmpty()==false;
00173 }
00174 RakString HTTPConnection::Read(void)
00175 {
00176         if (results.IsEmpty())
00177                 return RakString();
00178 
00179         RakNet::RakString resultStr = results.Pop();
00180     // const char *start_of_body = strstr(resultStr.C_String(), "\r\n\r\n");
00181         const char *start_of_body = strpbrk(resultStr.C_String(), "\001\002\003%");
00182     
00183     if(! start_of_body)
00184     {
00185                 return RakString();
00186     }
00187 
00188         // size_t len = strlen(start_of_body);
00189         //printf("Returning result with length %i\n", len);
00190         return RakNet::RakString::NonVariadic(start_of_body);
00191 }
00192 SystemAddress HTTPConnection::GetServerAddress(void) const
00193 {
00194         return server;
00195 }
00196 void HTTPConnection::ProcessTCPPacket(Packet *packet)
00197 {
00198         RakAssert(packet);
00199 
00200         // read all the packets possible
00201         if(packet->systemAddress == server)
00202         {
00203                 if(incomingData.GetLength() == 0)
00204                 {
00205                         int response_code = atoi((char *)packet->data + strlen("HTTP/1.0 "));
00206 
00207                         if(response_code > 299)
00208                         {
00209                                 badResponses.Push(BadResponse(packet->data, response_code), __FILE__, __LINE__ );
00210                                 //printf("Closed connection (Bad response 2)\n");
00211                                 CloseConnection();
00212                                 return;
00213                         }
00214                 }
00215 
00216                 RakNet::RakString incomingTemp = RakNet::RakString::NonVariadic((const char*) packet->data);
00217                 incomingTemp.URLDecode();
00218                 incomingData += incomingTemp;
00219 
00220         //      printf((const char*) packet->data);
00221         //      printf("\n");
00222 
00223                 RakAssert(strlen((char *)packet->data) == packet->length); // otherwise it contains Null bytes
00224 
00225                 const char *start_of_body = strstr(incomingData, "\r\n\r\n");
00226 
00227                 // besides having the server close the connection, they may
00228                 // provide a length header and supply that many bytes
00229                 if(start_of_body && connectionState == CS_PROCESSING)
00230                 {
00231                         /*
00232                         // The stupid programmer that wrote this originally didn't think that just because the header contains this value doesn't mean you got the whole message
00233                         if (strstr((const char*) packet->data, "\r\nConnection: close\r\n"))
00234                         {
00235                                 CloseConnection();
00236                         }
00237                         else
00238                         {
00239                         */
00240                                 long length_of_headers = (long)(start_of_body + 4 - incomingData.C_String());
00241 
00242                                 const char *length_header = strstr(incomingData, "\r\nLength: ");
00243                                 if(length_header)
00244                                 {
00245                                         long length = atol(length_header + 10) + length_of_headers;
00246 
00247                                         if((long) incomingData.GetLength() >= length)
00248                                         {
00249                                                 //printf("Closed connection (Got all data due to length header)\n");
00250                                                 CloseConnection();
00251                                         }
00252                                 }
00253                         //}
00254                 }
00255         }
00256 }
00257 
00258 bool HTTPConnection::IsBusy(void) const
00259 {
00260         return connectionState != CS_NONE;
00261 }
00262 
00263 int HTTPConnection::GetState(void) const
00264 {
00265         return connectionState;
00266 }
00267 
00268 
00269 HTTPConnection::~HTTPConnection(void)
00270 {
00271         if (tcp)
00272                 tcp->CloseConnection(server);
00273 }
00274 
00275 
00276 #endif // _RAKNET_SUPPORT_*

Generated on Thu Sep 30 2010 01:27:24 for RakNet by  doxygen 1.7.1