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
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
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
00086 CloseConnection();
00087 sa = tcp->HasFailedConnectionAttempt();
00088 }
00089
00090 sa = tcp->HasLostConnection();
00091 while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
00092 {
00093
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
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
00132 if (outgoingPosts.IsEmpty())
00133 {
00134
00135 CloseConnection();
00136 return;
00137 }
00138
00139 #if defined(OPEN_SSL_CLIENT_SUPPORT)
00140 tcp->StartSSLClient(server);
00141 #endif
00142
00143
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
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
00168
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
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
00189
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
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
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
00221
00222
00223 RakAssert(strlen((char *)packet->data) == packet->length);
00224
00225 const char *start_of_body = strstr(incomingData, "\r\n\r\n");
00226
00227
00228
00229 if(start_of_body && connectionState == CS_PROCESSING)
00230 {
00231
00232
00233
00234
00235
00236
00237
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
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_*