HTTP.cpp
Go to the documentation of this file.00001 //*** HTTP.cpp *** 00002 00003 #include "HTTP.h" 00004 #include "Platform_Network.h" 00005 #include "Platform_Network_Client.h" 00006 #include "StandardLibrary.h" 00007 #include "HTTP_Resource.h" 00008 #include "ArrayIterator.h" 00009 00010 00011 00012 //*** Constructor*** 00013 00014 HTTP::HTTP(): 00015 currentRequestHandle_(0) 00016 { 00017 } 00018 00019 00020 //*** Destructor *** 00021 00022 HTTP::~HTTP() 00023 { 00024 while (requests_.GetItemCount()>0) 00025 { 00026 DiscardRequest(requests_.Get(0)->handle); 00027 } 00028 00029 } 00030 00031 00032 //*** Update *** 00033 00034 void HTTP::Update(float deltaTime) 00035 { 00036 for (int i=0; i<requests_.GetItemCount(); i++) 00037 { 00038 Request* request=requests_.Get(i); 00039 00040 // Process the request depending on its current status 00041 switch (request->status) 00042 { 00043 case Status_Connecting: 00044 { 00045 if (request->connection && request->connection->IsConnected()) 00046 { 00047 // Define the template for HTTP Get header 00048 const char* headerGet="GET %s HTTP/1.0\r\nHost: %s:%d\r\n\r\n"; 00049 const char* headerPost="POST %s HTTP/1.0\r\nHost: %s:%d\r\nContent-Length: %d\r\n\r\n"; 00050 const char* header=0; 00051 if (request->usingGetMethod) 00052 { 00053 header=headerGet; 00054 } 00055 else 00056 { 00057 header=headerPost; 00058 } 00059 00060 00061 // Calculate maximum length of request string 00062 int maxLength=StrLen(header)+StrLen(request->requestString)+StrLen(request->connection->GetAddress())+10; 00063 00064 // Build request string 00065 char* requestString=new char[maxLength]; 00066 SNPrintF(requestString,maxLength,header,request->requestString,request->connection->GetAddress(),request->connection->GetPort(),request->postData.GetSize()); 00067 00068 // Send HTTP request 00069 request->connection->SendData(requestString,StrLen(requestString)); 00070 if (!request->usingGetMethod) 00071 { 00072 request->connection->SendData(request->postData.GetPointer(),request->postData.GetSize()); 00073 } 00074 00075 // Release request string 00076 delete[] requestString; 00077 00078 // Change request status to wait for result 00079 request->status=Status_Pending; 00080 } 00081 } break; 00082 00083 case Status_Pending: 00084 { 00085 // Are there any data to receive? 00086 if (request->connection && request->connection->GetReceivedDataSize()>0) 00087 { 00088 // Is this the first chunk of data we receive? 00089 bool firstChunk=false; 00090 if (request->receivedData.GetSize()==0) 00091 { 00092 firstChunk=true; 00093 } 00094 00095 // Receive the data (will be added to the end of the buffer) 00096 request->connection->GetReceivedData(&request->receivedData); 00097 00098 // If this is the first chunk we receive, we need to process the header 00099 if (firstChunk) 00100 { 00101 // Check Status Line 00102 char* statusLine=static_cast<char*>(request->receivedData.GetPointer()); 00103 00104 // Get header size 00105 int headerSize=0; 00106 const char* headerEnd=StrStr(statusLine,"\r\n\r\n"); 00107 if (headerEnd) 00108 { 00109 headerEnd+=4; 00110 headerSize=(int)(headerEnd-statusLine); 00111 } 00112 00113 // Extract httpVersion 00114 char httpVersion[256]; 00115 const char* ptr=StrChr(statusLine,' '); 00116 StrNCpy(httpVersion,statusLine,Min((int)(ptr-statusLine),255)); 00117 httpVersion[ptr-statusLine]=0; 00118 ptr++; 00119 00120 // Extract statusCode 00121 char statusCode[256]; 00122 const char* ptr2=StrChr(ptr,' '); 00123 StrNCpy(statusCode,ptr,Min((int)(ptr2-ptr),255)); 00124 statusCode[ptr2-ptr]=0; 00125 ptr2++; 00126 00127 // Extract reasonPhrase 00128 char reasonPhrase[256]; 00129 const char* ptr3=StrStr(ptr2,"\r\n"); 00130 StrNCpy(reasonPhrase,ptr2,Min((int)(ptr3-ptr2),255)); 00131 reasonPhrase[ptr3-ptr2]=0; 00132 ptr3++; 00133 00134 // Extract contentLength 00135 char contentLengthStr[256]; 00136 StrCpy(contentLengthStr,"0"); 00137 const char* ptr4=StrStr(ptr3,"Content-Length: "); 00138 if (ptr4) 00139 { 00140 ptr4+=16; 00141 const char* ptr5=StrStr(ptr4,"\r\n"); 00142 StrNCpy(contentLengthStr,ptr4,Min((int)(ptr5-ptr4),255)); 00143 contentLengthStr[ptr5-ptr4]=0; 00144 } 00145 00146 char contentTypeStr[256]; 00147 StrCpy(contentTypeStr,""); 00148 const char* ptr6=StrStr(ptr3,"Content-Type: "); 00149 if (ptr6) 00150 { 00151 ptr6+=14; 00152 const char* ptr7=StrStr(ptr6,"\r\n"); 00153 StrNCpy(contentTypeStr,ptr6,Min((int)(ptr7-ptr6),255)); 00154 contentTypeStr[ptr7-ptr6]=0; 00155 } 00156 00157 00158 // Check status 00159 int status=StringToInt(statusCode); 00160 int contentLength=StringToInt(contentLengthStr); 00161 StringId contentType=StringId(contentTypeStr); 00162 00163 if (status!=200 || contentLength==0 || contentType==StringId("")) 00164 { 00165 request->status=Status_Failed; 00166 } 00167 else 00168 { 00169 request->headerLength=headerSize; 00170 request->contentType=contentType; 00171 request->contentLength=contentLength; 00172 } 00173 } 00174 00175 // Check for dropped connection 00176 if (!request->connection->IsConnected()) 00177 { 00178 request->status=Status_Failed; 00179 } 00180 00181 // Check if we've received the whole resource 00182 if (request->status!=Status_Failed && request->receivedData.GetSize()==(unsigned int)request->contentLength+request->headerLength) 00183 { 00184 request->status=Status_Completed; 00185 00186 if (request->resource) 00187 { 00188 delete request->resource; 00189 } 00190 char* data=static_cast<char*>(request->receivedData.GetPointer()); 00191 data+=request->headerLength; 00192 StaticBuffer buffer(data,request->contentLength); 00193 request->resource=new HTTP_Resource(request->handle,request->contentType,buffer); 00194 } 00195 00196 } 00197 } break; 00198 00199 } 00200 00201 if (request->status==Status_Connecting || request->status==Status_Pending) 00202 { 00203 // Increase the elapsed time 00204 request->elapsedTime_+=deltaTime; 00205 00206 if (request->timeOut_>0.0f && request->elapsedTime_>request->timeOut_) 00207 { 00208 request->status=Status_TimedOut; 00209 } 00210 } 00211 } 00212 00213 } 00214 00215 00216 //*** Request_Get *** 00217 00218 int HTTP::Request_Get(const char* url, float timeOut) 00219 { 00220 // Create new request entry, and add it to list of request entries 00221 Request* request=new Request; 00222 currentRequestHandle_++; 00223 request->handle=currentRequestHandle_; 00224 request->usingGetMethod=true; 00225 request->status=Status_Connecting; 00226 request->timeOut_=timeOut; 00227 request->elapsedTime_=0; 00228 request->connection=0; 00229 request->requestString=0; 00230 request->contentLength=0; 00231 request->resource=0; 00232 requests_.Add(request); 00233 00234 // Make sure URL starts with http:// 00235 if (StrNICmp(url,"http://",7)!=0) 00236 { 00237 request->status=Status_Failed; 00238 return request->handle; 00239 } 00240 00241 // Split URL string 00242 char* address=0; 00243 char* port=0; 00244 char* requestString=0; 00245 SplitURL(url,address,port,requestString); 00246 00247 // Create connection 00248 if (Platform::GetPlatform_Network()) 00249 { 00250 request->connection=Platform::GetPlatform_Network()->CreateClient(Platform_Network::ConnectionMode_TCP,address,StringToInt(port)); 00251 } 00252 if (!request->connection->Connect()) 00253 { 00254 request->status=Status_Failed; 00255 } 00256 00257 // Store request string 00258 request->requestString=StrDup(requestString); 00259 00260 // Clean up after SplitURL 00261 delete[] requestString; 00262 delete[] port; 00263 delete[] address; 00264 00265 // Return handle to this request 00266 return request->handle; 00267 } 00268 00269 00270 //*** Request_Post *** 00271 00272 int HTTP::Request_Post(const char* url, const void* data, int size, float timeOut) 00273 { 00274 // Create new request entry, and add it to list of request entries 00275 Request* request=new Request; 00276 currentRequestHandle_++; 00277 request->handle=currentRequestHandle_; 00278 request->usingGetMethod=false; 00279 request->status=Status_Connecting; 00280 request->timeOut_=timeOut; 00281 request->elapsedTime_=0; 00282 request->connection=0; 00283 request->requestString=0; 00284 request->contentLength=0; 00285 request->resource=0; 00286 request->postData.Write(static_cast<const char*>(data),size); 00287 requests_.Add(request); 00288 00289 // Make sure URL starts with http:// 00290 if (StrNICmp(url,"http://",7)!=0) 00291 { 00292 request->status=Status_Failed; 00293 return request->handle; 00294 } 00295 00296 // Split URL string 00297 char* address=0; 00298 char* port=0; 00299 char* requestString=0; 00300 SplitURL(url,address,port,requestString); 00301 00302 // Create connection 00303 if (Platform::GetPlatform_Network()) 00304 { 00305 request->connection=Platform::GetPlatform_Network()->CreateClient(Platform_Network::ConnectionMode_TCP,address,StringToInt(port)); 00306 } 00307 if (!request->connection->Connect()) 00308 { 00309 request->status=Status_Failed; 00310 } 00311 00312 // Store request string 00313 request->requestString=StrDup(requestString); 00314 00315 // Clean up after SplitURL 00316 delete[] requestString; 00317 delete[] port; 00318 delete[] address; 00319 00320 // Return handle to this request 00321 return request->handle; 00322 } 00323 00324 00325 //*** GetRequestStatus *** 00326 00327 HTTP::RequestStatus HTTP::GetRequestStatus(int requestHandle) 00328 { 00329 Request* request=GetRequest(requestHandle); 00330 00331 if (request) 00332 { 00333 return request->status; 00334 } 00335 00336 return Status_Invalid; 00337 } 00338 00339 00340 //*** GetPercentageReceived *** 00341 00342 float HTTP::GetPercentageReceived(int requestHandle) 00343 { 00344 Request* request=GetRequest(requestHandle); 00345 00346 if (request && request->contentLength>0 && request->headerLength>0) 00347 { 00348 return (float)request->receivedData.GetSize()/(float)(request->contentLength+request->headerLength); 00349 } 00350 00351 return 0.0f; 00352 } 00353 00354 00355 //*** GetResource *** 00356 00357 HTTP_Resource* HTTP::GetResource(int requestHandle) 00358 { 00359 Request* request=GetRequest(requestHandle); 00360 return request->resource; 00361 } 00362 00363 00364 //*** DiscardRequest *** 00365 00366 void HTTP::DiscardRequest(int requestHandle) 00367 { 00368 Request* request=GetRequest(requestHandle); 00369 00370 if (request) 00371 { 00372 if (request->connection) 00373 { 00374 delete request->connection; 00375 } 00376 if (request->requestString) 00377 { 00378 Free(request->requestString); 00379 } 00380 if (request->resource) 00381 { 00382 delete request->resource; 00383 } 00384 ArrayIterator<Request*> it(requests_); 00385 if (it.Find(request)) 00386 { 00387 requests_.Remove(it); 00388 } 00389 delete request; 00390 } 00391 00392 } 00393 00394 00395 //*** GetRequest *** 00396 00397 HTTP::Request* HTTP::GetRequest(int requestHandle) 00398 { 00399 for (int i=0; i<requests_.GetItemCount(); i++) 00400 { 00401 Request* request=requests_.Get(i); 00402 if (request->handle==requestHandle) 00403 { 00404 return request; 00405 } 00406 } 00407 00408 return 0; 00409 } 00410 00411 00412 //*** SplitURL *** 00413 00414 void HTTP::SplitURL(const char* url, char*& address, char*&port, char*& resource) 00415 { 00416 // Skip http:// part of url 00417 url+=7; 00418 00419 // Find end of address part of URL 00420 const char* addressEnd=StrChr(url,':'); 00421 if (addressEnd==0) 00422 { 00423 addressEnd=StrChr(url,'/'); 00424 } 00425 if (addressEnd==0) 00426 { 00427 addressEnd=url+StrLen(url); 00428 } 00429 00430 // Extract address 00431 address=new char[addressEnd-url+1]; 00432 StrNCpy(address,url,(int)(addressEnd-url)); 00433 address[addressEnd-url]=0; 00434 00435 // Check if there's a port defined 00436 port=new char[StrLen(addressEnd)+5]; 00437 const char* portEnd=addressEnd; 00438 StrCpy(port,"80"); 00439 if (*addressEnd==':') 00440 { 00441 addressEnd++; 00442 portEnd=StrChr(addressEnd,'/'); 00443 if (portEnd==0) 00444 { 00445 portEnd=addressEnd+StrLen(addressEnd); 00446 } 00447 StrNCpy(port,addressEnd,(int)(portEnd-addressEnd)); 00448 port[portEnd-addressEnd]=0; 00449 } 00450 00451 00452 // Check if there's a resource defined 00453 resource=new char[StrLen(portEnd)+5]; 00454 StrCpy(resource,"/"); 00455 if (*portEnd=='/') 00456 { 00457 StrCpy(resource,portEnd); 00458 } 00459 00460 }
Reproduction/republishing of any material on this site without permission is strictly prohibited.
