00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "stdafx.h"
00032 #include "httpfilesource.h"
00033
00034
00035 HTTPFileSource::HTTPFileSource(void)
00036 : mBufferLock(NULL)
00037 , mIsChunked(false)
00038 , mIsFirstChunk(true)
00039 , mChunkRemains(0)
00040 , mNumLeftovers(0)
00041 {
00042 mBufferLock = new CCritSec;
00043 #ifdef OGGCODECS_LOGGING
00044 debugLog.open("d:\\zen\\logs\\htttp.log", ios_base::out | ios_base::app);
00045 fileDump.open("d:\\zen\\logs\\filedump.ogg", ios_base::out|ios_base::binary);
00046 rawDump.open("D:\\zen\\logs\\rawdump.out", ios_base::out|ios_base::binary);
00047 #endif
00048 mInterBuff = new unsigned char[RECV_BUFF_SIZE* 2];
00049
00050 }
00051
00052 HTTPFileSource::~HTTPFileSource(void)
00053 {
00054
00055 close();
00056
00057 #ifdef OGGCODECS_LOGGING
00058 debugLog.close();
00059 fileDump.close();
00060 rawDump.close();
00061 #endif
00062 delete mBufferLock;
00063 delete mInterBuff;
00064 }
00065
00066 void HTTPFileSource::unChunk(unsigned char* inBuff, unsigned long inNumBytes)
00067 {
00068
00069
00070 ASSERT(inNumBytes > 2);
00071 rawDump.write((char*)inBuff, inNumBytes);
00072 debugLog<<"UnChunk"<<endl;
00073 unsigned long locNumBytesLeft = inNumBytes;
00074
00075 memcpy((void*)(mInterBuff + mNumLeftovers), (const void*)inBuff, inNumBytes);
00076 locNumBytesLeft += mNumLeftovers;
00077 mNumLeftovers = 0;
00078 unsigned char* locWorkingBuffPtr = mInterBuff;
00079
00080
00081
00082 while (locNumBytesLeft > 8) {
00083
00084
00085
00086
00087 if (mChunkRemains == 0) {
00088
00089
00090
00091 string locTemp;
00092
00093 if (mIsFirstChunk) {
00094
00095 mIsFirstChunk = false;
00096 locTemp = (char*)locWorkingBuffPtr;
00097 } else {
00098
00099
00100 locTemp = (char*)(locWorkingBuffPtr + 2);
00101 locWorkingBuffPtr+=2;
00102 locNumBytesLeft -= 2;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111 size_t locChunkSizePos = locTemp.find("\r\n");
00112
00113
00114 if (locChunkSizePos != string::npos) {
00115
00116
00117 string locChunkSizeStr = locTemp.substr(0, locChunkSizePos);
00118
00119 char* locDummyPtr = NULL;
00120
00121
00122 mChunkRemains = strtol(locChunkSizeStr.c_str(), &locDummyPtr, 16);
00123
00124
00125
00126 unsigned long locGuffSize = (unsigned long)(locChunkSizeStr.size() + 2);
00127 locWorkingBuffPtr += locGuffSize;
00128 locNumBytesLeft -= locGuffSize;
00129 } else {
00130
00131
00132
00133 }
00134 }
00135
00136
00137 if (mChunkRemains == 0) {
00138
00139 return;
00140 }
00141
00142
00143 if (locNumBytesLeft < mChunkRemains) {
00144
00145
00146 mFileCache.write((const unsigned char*)locWorkingBuffPtr, locNumBytesLeft );
00147 fileDump.write((char*)locWorkingBuffPtr, locNumBytesLeft);
00148 locWorkingBuffPtr += locNumBytesLeft;
00149 mChunkRemains -= locNumBytesLeft;
00150 locNumBytesLeft = 0;
00151 } else {
00152
00153 mFileCache.write((const unsigned char*)locWorkingBuffPtr, mChunkRemains );
00154 fileDump.write((char*)locWorkingBuffPtr, mChunkRemains);
00155 locWorkingBuffPtr += mChunkRemains;
00156 locNumBytesLeft -= mChunkRemains;
00157 mChunkRemains = 0;
00158 }
00159
00160 }
00161
00162 if (locNumBytesLeft != 0) {
00163
00164 memcpy((void*)mInterBuff, (const void*)locWorkingBuffPtr, locNumBytesLeft);
00165 mNumLeftovers = locNumBytesLeft;
00166 }
00167 }
00168 void HTTPFileSource::DataProcessLoop() {
00169
00170 int locNumRead = 0;
00171 char* locBuff = NULL;
00172 DWORD locCommand = 0;
00173 bool locSeenAny = false;
00174 debugLog<<"Starting dataprocessloop"<<endl;
00175
00176 locBuff = new char[RECV_BUFF_SIZE];
00177
00178 while(true) {
00179 if(CheckRequest(&locCommand) == TRUE) {
00180 debugLog<<"Thread Data Process loop received breakout signal..."<<endl;
00181 delete[] locBuff;
00182 return;
00183 }
00184
00185 locNumRead = recv(mSocket, locBuff, RECV_BUFF_SIZE, 0);
00186
00187 if (locNumRead == SOCKET_ERROR) {
00188 int locErr = WSAGetLastError();
00189 debugLog<<"Socket error receiving - Err No = "<<locErr<<endl;
00190 mWasError = true;
00191 break;
00192 }
00193
00194 if (locNumRead == 0) {
00195 debugLog<<"Read last bytes..."<<endl;
00196 mIsEOF = true;
00197 delete[] locBuff;
00198 return;
00199 }
00200
00201 {
00202 CAutoLock locLock(mBufferLock);
00203
00204 if (mSeenResponse) {
00205
00206
00207 if (mIsChunked) {
00208 unChunk((unsigned char*)locBuff, locNumRead);
00209 } else {
00210 mFileCache.write((const unsigned char*)locBuff, locNumRead);
00211 }
00212
00213
00214
00215 } else {
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 string locTemp = locBuff;
00226
00227 size_t locPos = locTemp.find("\r\n\r\n");
00228 if (locPos != string::npos) {
00229
00230
00231 mSeenResponse = true;
00232 mLastResponse = locTemp.substr(0, locPos);
00233 debugLog<<"HTTP Response:"<<endl;
00234 debugLog<<mLastResponse<<endl;
00235
00236 unsigned short locResponseCode = getHTTPResponseCode(mLastResponse);
00237
00238 mRetryAt = "";
00239 if (locResponseCode == 301) {
00240 size_t locLocPos = mLastResponse.find("Location: ");
00241 if (locLocPos != string::npos) {
00242 locLocPos += 10;
00243 size_t locEndPos = mLastResponse.find("\r", locLocPos);
00244 if (locEndPos != string::npos) {
00245 if (locEndPos > locLocPos) {
00246 mRetryAt = mLastResponse.substr(locLocPos, locEndPos - locLocPos);
00247 debugLog<<"Retry URL = "<<mRetryAt<<endl;
00248 }
00249 }
00250 }
00251
00252 debugLog<<"Setting error to true"<<endl;
00253 mIsEOF = true;
00254 mWasError = true;
00255
00256 } else if (locResponseCode >= 300) {
00257 debugLog<<"Setting error to true"<<endl;
00258 mIsEOF = true;
00259 mWasError = true;
00260
00261 }
00262
00263 if (locTemp.find("Transfer-Encoding: chunked") != string::npos) {
00264 mIsChunked = true;
00265 }
00266
00267 char* locBuff2 = locBuff + locPos + 4;
00268 locTemp = locBuff2;
00269
00270 if (mIsChunked) {
00271 if (locNumRead - locPos - 4 > 0) {
00272 unChunk((unsigned char*)locBuff2, locNumRead - locPos - 4);
00273 }
00274 } else {
00275
00276 if (locNumRead - locPos - 4 > 0) {
00277 mFileCache.write((const unsigned char*)locBuff2, (locNumRead - (locPos + 4)));
00278 }
00279 }
00280 }
00281 }
00282 }
00283 }
00284
00285 delete[] locBuff;
00286 }
00287
00288 unsigned short HTTPFileSource::getHTTPResponseCode(string inHTTPResponse)
00289 {
00290 size_t locPos = inHTTPResponse.find(" ");
00291 if (locPos != string::npos) {
00292 string locCodeString = inHTTPResponse.substr(locPos + 1, 3);
00293 try {
00294 unsigned short locCode = (unsigned short)StringHelper::stringToNum(locCodeString);
00295 return locCode;
00296 } catch(...) {
00297 return 0;
00298 }
00299 } else {
00300 return 0;
00301 }
00302 }
00303 string HTTPFileSource::shouldRetryAt()
00304 {
00305 return mRetryAt;
00306 }
00307
00308 DWORD HTTPFileSource::ThreadProc(void) {
00309
00310 while(true) {
00311 DWORD locThreadCommand = GetRequest();
00312
00313 switch(locThreadCommand) {
00314 case THREAD_EXIT:
00315
00316 Reply(S_OK);
00317 return S_OK;
00318
00319 case THREAD_RUN:
00320
00321 Reply(S_OK);
00322 DataProcessLoop();
00323 break;
00324 }
00325
00326
00327 }
00328 return S_OK;
00329 }
00330 unsigned long HTTPFileSource::seek(unsigned long inPos) {
00331
00332
00333
00334
00335 if (mFileCache.readSeek(inPos)) {
00336 return inPos;
00337 } else {
00338 return (unsigned long) -1;
00339 }
00340
00341 }
00342
00343
00344 void HTTPFileSource::close() {
00345
00346
00347 if (ThreadExists() == TRUE) {
00348
00349 CallWorker(THREAD_EXIT);
00350
00351 Close();
00352
00353 }
00354
00355
00356
00357
00358
00359 closeSocket();
00360 }
00361
00362 bool HTTPFileSource::startThread() {
00363 if (ThreadExists() == FALSE) {
00364 Create();
00365 }
00366 CallWorker(THREAD_RUN);
00367 return true;
00368 }
00369 bool HTTPFileSource::open(string inSourceLocation) {
00370
00371
00372 mSeenResponse = false;
00373 mLastResponse = "";
00374
00375
00376 {
00377 CAutoLock locLock(mBufferLock);
00378
00379
00380 LARGE_INTEGER locTicks;
00381 QueryPerformanceCounter(&locTicks);
00382 srand((unsigned int)locTicks.LowPart);
00383
00384 int locRand = rand();
00385
00386 string locCacheFileName = getenv("TEMP");
00387
00388 locCacheFileName += "\\filecache";
00389
00390 locCacheFileName += StringHelper::numToString(locRand);
00391 locCacheFileName += ".ogg";
00392
00393 if(mFileCache.open(locCacheFileName)) {
00394
00395 }
00396 }
00397
00398 bool locIsOK = setupSocket(inSourceLocation);
00399
00400 if (!locIsOK) {
00401
00402 closeSocket();
00403 return false;
00404 }
00405
00406
00407
00408
00409 httpRequest(assembleRequest(mFileName));
00410
00411 locIsOK = startThread();
00412
00413
00414 return locIsOK;
00415 }
00416 void HTTPFileSource::clear() {
00417
00418 debugLog<<"Setting error to false";
00419 mIsEOF = false;
00420 mWasError = false;
00421 mRetryAt = "";
00422 }
00423 bool HTTPFileSource::isError()
00424 {
00425 return mWasError;
00426 }
00427 bool HTTPFileSource::isEOF() {
00428 {
00429 CAutoLock locLock(mBufferLock);
00430 unsigned long locSizeBuffed = mFileCache.bytesAvail();;
00431
00432
00433 if ((locSizeBuffed == 0) && mIsEOF) {
00434
00435 return true;
00436 } else {
00437
00438 return false;
00439 }
00440 }
00441
00442 }
00443 unsigned long HTTPFileSource::read(char* outBuffer, unsigned long inNumBytes) {
00444
00445
00446
00447 {
00448 CAutoLock locLock(mBufferLock);
00449
00450
00451 if((mFileCache.bytesAvail() == 0) || mWasError) {
00452
00453 return 0;
00454 } else {
00455 debugLog<<"Reading from buffer"<<endl;
00456
00457 unsigned long locNumRead = mFileCache.read((unsigned char*)outBuffer, inNumBytes);
00458
00459
00460 return locNumRead;
00461 }
00462 }
00463 }