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
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 }
00329 return S_OK;
00330 }
00331 unsigned long HTTPFileSource::seek(unsigned long inPos) {
00332
00333
00334
00335
00336 if (mFileCache.readSeek(inPos)) {
00337 return inPos;
00338 } else {
00339 return (unsigned long) -1;
00340 }
00341
00342 }
00343
00344
00345 void HTTPFileSource::close() {
00346
00347
00348 if (ThreadExists() == TRUE) {
00349
00350 CallWorker(THREAD_EXIT);
00351
00352 Close();
00353
00354 }
00355
00356
00357
00358
00359
00360 closeSocket();
00361 }
00362
00363 bool HTTPFileSource::startThread() {
00364 if (ThreadExists() == FALSE) {
00365 Create();
00366 }
00367 CallWorker(THREAD_RUN);
00368 return true;
00369 }
00370 bool HTTPFileSource::open(string inSourceLocation, unsigned long inStartByte) {
00371
00372
00373 mSeenResponse = false;
00374 mLastResponse = "";
00375
00376
00377 {
00378 CAutoLock locLock(mBufferLock);
00379
00380
00381 LARGE_INTEGER locTicks;
00382 QueryPerformanceCounter(&locTicks);
00383 srand((unsigned int)locTicks.LowPart);
00384
00385 int locRand = rand();
00386
00387 string locCacheFileName = getenv("TEMP");
00388
00389 locCacheFileName += "\\filecache";
00390
00391 locCacheFileName += StringHelper::numToString(locRand);
00392 locCacheFileName += ".ogg";
00393
00394 if(mFileCache.open(locCacheFileName)) {
00395
00396 }
00397 }
00398
00399 bool locIsOK = setupSocket(inSourceLocation);
00400
00401 if (!locIsOK) {
00402
00403 closeSocket();
00404 return false;
00405 }
00406
00407
00408
00409
00410 httpRequest(assembleRequest(mFileName));
00411
00412 locIsOK = startThread();
00413
00414
00415 return locIsOK;
00416 }
00417 void HTTPFileSource::clear() {
00418
00419 debugLog<<"Setting error to false";
00420 mIsEOF = false;
00421 mWasError = false;
00422 mRetryAt = "";
00423 }
00424 bool HTTPFileSource::isError()
00425 {
00426 return mWasError;
00427 }
00428 bool HTTPFileSource::isEOF() {
00429 {
00430 CAutoLock locLock(mBufferLock);
00431 unsigned long locSizeBuffed = mFileCache.bytesAvail();;
00432
00433
00434 if ((locSizeBuffed == 0) && mIsEOF) {
00435
00436 return true;
00437 } else {
00438
00439 return false;
00440 }
00441 }
00442
00443 }
00444 unsigned long HTTPFileSource::read(char* outBuffer, unsigned long inNumBytes) {
00445
00446
00447
00448 {
00449 CAutoLock locLock(mBufferLock);
00450
00451
00452 if((mFileCache.bytesAvail() == 0) || mWasError) {
00453
00454 return 0;
00455 } else {
00456
00457
00458 unsigned long locNumRead = mFileCache.read((unsigned char*)outBuffer, inNumBytes);
00459
00460 if (locNumRead > 0) {
00461 debugLog<<locNumRead<<" bytes read from buffer"<<endl;
00462 }
00463 return locNumRead;
00464 }
00465 }
00466 }