📄 sbinethttpstream.cpp
字号:
// Rather than Sleep and Wake on timers, lets try increasing timeouts // worse case, process should take 128ms more than necessary. if(sleepTime < 100) sleepTime *= 2; } if((m_HttpStatus < 0) || !((m_HttpStatus/100 == 2) || (m_HttpStatus == 304))){ Error(219, L"%s%s%s%s%s%d", L"URL", m_url->GetAbsolute(), L"Method", (m_method == GET_METHOD) ? L"GET" : L"POST", L"Error", m_HttpStatus); Close(); return(MapError(m_HttpStatus)); } /* * Success */ // Init for reading m_ReadSoFar = 0; SBinetInterface::LockLibwww( ); // clean up -- we seem to be able to delete and flush in either order. // flush calls the after filters, so delete first?? HTRequest_deleteAfterAll(m_request); // Why do we flush?? -- If we don't we crash!!! HTRequest_forceFlush(m_request); // Get header info GetHeaderInfo(streamInfo); SBinetInterface::UnlockLibwww( ); if((validatorVal != NULL) && (m_HttpStatus == 304)) { Close(); return VXIinet_RESULT_NOT_MODIFIED; } return VXIinet_RESULT_SUCCESS;}//// Read is the same for all HTTP requests (GET and POST)// At the moment, Read is not locks as merely copies data out of chunk//VXIinetResultSBinetHttpStream::Read(VXIbyte *buffer, VXIulong buflen, VXIulong *nread){ if(nread != NULL) *nread = 0L; if(m_chunk == NULL) { Error(221, NULL); return VXIinet_RESULT_FAILURE; } int len = HTChunk_size(m_chunk); int toRead = buflen; int remaining = len - m_ReadSoFar; if(remaining <= 0) return(VXIinet_RESULT_END_OF_STREAM); if(toRead > remaining) toRead = remaining; char* data = HTChunk_data(m_chunk); if(data == NULL) { Error(220, NULL); return VXIinet_RESULT_FAILURE; } data += m_ReadSoFar; ::memcpy( (void*)buffer, (void*)data, toRead ); m_ReadSoFar += toRead; if(nread != NULL) *nread = toRead; return(VXIinet_RESULT_SUCCESS);}VXIinetResultSBinetHttpStream::Close(){ // If no request (multiple calls to Close() are allowed), // check lock to make sure. if(m_request == NULL){ if(m_lock){ m_lock->FreeReadLock(m_request); // free lock on anchor m_lock = NULL; return(VXIinet_RESULT_SUCCESS); } } /* Clean up the request * Note: we might want to do the delete in the destructor to give libwww extra time * to settle down */ SBinetInterface::LockLibwww( ); if(m_chunk){ HTChunk_delete(m_chunk); m_chunk = NULL; } if(m_request){ HTRequest_kill( m_request ); HTRequest_delete(m_request); m_request = NULL; } if(m_lock){ m_lock->FreeReadLock(m_request); // free lock on anchor m_lock = NULL; } SBinetInterface::UnlockLibwww( ); /* * Might need to do Sleep here to let libwww timers settle out */ return(VXIinet_RESULT_SUCCESS);}SBinetHttpStream::SBinetHttpStream(SBinetURL* url, SBinetChannel* ch, VXIlogInterface *log, VXIunsigned diagLogBase): SBinetLogger(MODULE_SBINET_STREAM, log, diagLogBase), m_submitMimeType(), m_content_type(){ m_request = NULL; m_chunk = NULL; m_argstring = L""; // string representation of query ares for GET m_queryArgs = NULL; m_Done = 0; m_ReadSoFar = 0; m_HttpStatus = 0; m_url = url; m_iMaxAge = -1; m_iMaxStale = 0; m_nTimeoutOpen = 0; m_nTimeoutIO = 0; m_method = GET_METHOD; m_newAnchor = NULL; m_lock = NULL; m_content_length = 0; m_reader = 2; m_ch = ch;}SBinetHttpStream::~SBinetHttpStream(){ Close(); if(m_url) delete m_url;}voidSBinetHttpStream::SetProperties(VXIMap* properties){ const VXIString* strCachingMode = (const VXIString*)VXIMapGetProperty( properties, INET_CACHING ); const VXIInteger* intMaxAge = (const VXIInteger*)VXIMapGetProperty( properties, INET_CACHE_CONTROL_MAX_AGE ); const VXIInteger* intMaxStale = (const VXIInteger*)VXIMapGetProperty( properties, INET_CACHE_CONTROL_MAX_STALE ); // Cache control, INET_CACHING overrides the individual settings m_iMaxAge = -1; m_iMaxStale = 0; if ( intMaxAge != NULL ) m_iMaxAge = VXIIntegerValue(intMaxAge); if ( intMaxStale != NULL ) m_iMaxStale = VXIIntegerValue(intMaxStale); if (( strCachingMode != NULL ) && ( VXIStringCompareC( strCachingMode, INET_CACHING_SAFE ) == 0 )) { m_iMaxAge = 0; m_iMaxStale = 0; } // Open timeout m_nTimeoutOpen = INET_TIMEOUT_OPEN_DEFAULT * 10; // TBD wrong! VXIInteger *timeoutOpen = (VXIInteger *)VXIMapGetProperty( properties, INET_TIMEOUT_OPEN ); if( timeoutOpen != NULL ) m_nTimeoutOpen = VXIIntegerValue( timeoutOpen ); // IO timeout m_nTimeoutIO = INET_TIMEOUT_IO_DEFAULT; VXIInteger *timeoutIO = (VXIInteger *)VXIMapGetProperty( properties, INET_TIMEOUT_IO ); if( timeoutIO != NULL ) m_nTimeoutIO = VXIIntegerValue( timeoutIO ); // Get the submit MIME type from the properties, if defined const VXIchar* wType = INET_SUBMIT_MIME_TYPE_DEFAULT; VXIString *strType = (VXIString *)VXIMapGetProperty( properties, INET_SUBMIT_MIME_TYPE ); if ( strType ) wType = VXIStringCStr( strType ); m_submitMimeType = ""; size_t len = ::wcslen( wType ); for (size_t i = 0; i < len; i++) m_submitMimeType += (char) wType[i]; // Get the SUBMIT method from the properties, if defined wType = INET_SUBMIT_METHOD_DEFAULT; m_method = GET_METHOD; strType = (VXIString *)VXIMapGetProperty( properties, INET_SUBMIT_METHOD ); if ( strType ) { wType = VXIStringCStr( strType ); if ( !::wcscmp( wType, INET_SUBMIT_METHOD_GET )) m_method = GET_METHOD; else if ( !::wcscmp( wType, INET_SUBMIT_METHOD_POST )) m_method = POST_METHOD; } // Get the query arguments, if defined m_queryArgs = (VXIMap *)VXIMapGetProperty( properties, INET_URL_QUERY_ARGS );}VXIinetResult SBinetHttpStream::SetCachingMode( ){ if ( m_iMaxAge == 0 ) { // We always want to check Modified and Validator HTRequest_addRqHd(m_request, HT_C_IF_NONE_MATCH ); HTRequest_addRqHd(m_request, HT_C_IMS); // We may have to use _VALIDATE rather then _END_VALIDATE for // the non-proxy case to avoid gratuitous downloads HTRequest_setReloadMode( m_request, HT_CACHE_END_VALIDATE ); } else { HTRequest_setReloadMode( m_request, HT_CACHE_OK ); } return VXIinet_RESULT_SUCCESS;}void SBinetHttpStream::GetHeaderInfo(VXIMap* streamInfo){ HTParentAnchor* anchor = HTRequest_anchor(m_request); int nStatus = m_HttpStatus; // Check if the HTTP return status is 200 (OK) or 304 (NOT_MODIFIED) if (( streamInfo != NULL ) && (( nStatus == 200 ) || ( nStatus == 304 ))){ // Set HTTP status VXIMapSetProperty(streamInfo, INET_INFO_HTTP_STATUS, (VXIValue*)VXIIntegerCreate( nStatus )); // Set the ABSOLUTE_NAME property to the URL returned by the server char *serverURL = HTAnchor_address((HTAnchor *)anchor); if(( serverURL != NULL ) && ( serverURL[0] != '\0' )){ VXIint len = ::strlen( serverURL ) + 1; VXIchar *wServerURL = new VXIchar [len]; ::mbstowcs( wServerURL, serverURL, len ); VXIMapSetProperty(streamInfo, INET_INFO_ABSOLUTE_NAME, (VXIValue*)VXIStringCreate( wServerURL )); delete [] wServerURL; } HT_FREE(serverURL); // HTAnchor_address does MALLOC or copy // Get relevant response fields m_content_length = HTAnchor_length(anchor); m_content_type = L""; VXIbool haveValidator = FALSE; SBinetValidator validator(GetLog(), GetDiagBase()); if (validator.Create(m_url->GetAbsolute(), HTAnchor_lastModified(anchor), HTAnchor_expires(anchor), m_content_length, HTAnchor_etag(anchor), HTAnchor_header(anchor)) == VXIinet_RESULT_SUCCESS) { validator.Log(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::GetHeaderInfo"); haveValidator = TRUE; } const char *contentType = HTAtom_name(HTAnchor_format(anchor)); if (( contentType ) && ( contentType[0] ) && ( ::strcmp(contentType, DEFAULT_GENERIC_MIME_TYPE_N) != 0 )) { size_t len = ::strlen(contentType); for (size_t i = 0; i < len; i++) m_content_type += (VXIchar) contentType[i]; } else { VXIinetResult rc = m_url->ContentTypeFromUrl(&m_content_type); if(rc == VXIinet_RESULT_SUCCESS) { Error (300, L"%s%s%s%s", L"url", m_url->GetAbsolute(), L"mime", m_content_type.c_str()); } else { m_content_type = DEFAULT_GENERIC_MIME_TYPE; Error (301, L"%s%s", L"url", m_url->GetAbsolute()); } } // Fill properties VXIMapSetProperty( streamInfo, INET_INFO_SIZE_BYTES, (VXIValue*)VXIIntegerCreate(m_content_length)); VXIMapSetProperty( streamInfo, INET_INFO_MIME_TYPE, (VXIValue*)VXIStringCreate(m_content_type.c_str())); if (haveValidator) VXIMapSetProperty(streamInfo, INET_INFO_VALIDATOR, (VXIValue*)validator.Serialize()); } // Ends if (streamInfo && HTTP200/304) }VXIinetResult SBinetHttpStream::MapError(int ht_error){ switch(ht_error) { case HT_NO_ACCESS: /* Unauthorized */ case HT_FORBIDDEN: /* Access forbidden */ case HT_NOT_ACCEPTABLE:/* Not Acceptable */ case HT_NO_PROXY_ACCESS: /* Proxy Authentication Failed */ case HT_CONFLICT: /* Conflict */ case HT_LENGTH_REQUIRED: /* Length required */ case HT_PRECONDITION_FAILED: /* Precondition failed */ case HT_TOO_BIG: /* Request entity too large */ case HT_URI_TOO_BIG: /* Request-URI too long */ case HT_UNSUPPORTED: /* Unsupported */ case HT_BAD_RANGE: /* Request Range not satisfiable */ case HT_EXPECTATION_FAILED: /* Expectation Failed */ case HT_REAUTH: /* Reauthentication required */ case HT_PROXY_REAUTH: /* Proxy Reauthentication required */ case HT_RETRY: /* If service isn't available */ case HT_BAD_VERSION: /* Bad protocol version */ return VXIinet_RESULT_FETCH_ERROR; case HT_INTERNAL: /* Weird -- should never happen. */ return VXIinet_RESULT_NON_FATAL_ERROR; case HT_WOULD_BLOCK: /* If we are in a select */ return VXIinet_RESULT_WOULD_BLOCK; case HT_INTERRUPTED: /* Note the negative value! */ case HT_PAUSE: /* If we want to pause a stream */ case HT_RECOVER_PIPE: /* Recover pipe line */ return VXIinet_RESULT_SUCCESS; case HT_TIMEOUT: /* Connection timeout */ return VXIinet_RESULT_FETCH_TIMEOUT; case HT_NOT_FOUND: /* Not found */ case HT_NO_HOST: /* Can't locate host */ return VXIinet_RESULT_NOT_FOUND; default: return VXIinet_RESULT_NON_FATAL_ERROR; }}/* * Return one if there is a non-expired cache copy and we can use it without validation */staticint CacheValid (HTRequest * request){ HTParentAnchor * anchor = HTRequest_anchor(request); char * default_name = HTRequest_defaultPutName (request); HTCache * cache = NULL; HTReload reload = HTRequest_reloadMode(request); HTMethod method = HTRequest_method(request); HTDisconnectedMode disconnect = HTCacheMode_disconnected(); BOOL validate = NO; /* ** If the cache is disabled all together then it won't help looking, huh? */ if (!HTCacheMode_enabled()) return(0); /* ** Now check the cache... */ if (method != METHOD_GET) { return(0); } else if (reload == HT_CACHE_FLUSH) { return(0); } else { /* ** Check the persistent cache manager. If we have a cache hit then ** continue to see if the reload mode requires us to do a validation ** check. This filter assumes that we can get the cached version ** through one of our protocol modules (for example the file module) */ cache = HTCache_find(anchor, default_name); if (cache) { HTReload cache_mode = HTCache_isFresh(cache, request); if (cache_mode == HT_CACHE_ERROR) cache = NULL; reload = HTMAX(reload, cache_mode); /* ** Now check the mode and add the right headers for the validation ** If we are to validate a cache entry then we get a lock ** on it so that not other requests can steal it. */ if (reload == HT_CACHE_RANGE_VALIDATE) { return(0); } else if (reload == HT_CACHE_END_VALIDATE) { return(0); } else if (reload == HT_CACHE_VALIDATE) { return(0); } else if (cache) { /* ** The entity does not require any validation at all. We ** can just go ahead and get it from the cache. In case we ** have a fresh subpart of the entity, then we issue a ** conditional GET request with the range set by the cache ** manager. Issuing the conditional range request is ** equivalent to a validation as we have to go out on the ** net. This may have an effect if running in disconnected ** mode. We disable all BEFORE filters as they don't make ** sense while loading the cache entry. */ return(1); } } } return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -