📄 sbinethttpstream.cpp
字号:
/****************License************************************************ * * Copyright 2001. SpeechWorks International, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.1 which is * included with this software. * * SpeechWorks is a registered trademark, and SpeechWorks Here, * DialogModules and the SpeechWorks logo are trademarks of SpeechWorks * International, Inc. in the United States and other countries. * *********************************************************************** * * SBinetHttpStream Implementation * * $Id: SBinetHttpStream.cpp,v 1.38.2.1.2.9 2001/11/14 16:35:04 ddeac Exp $ * ***********************************************************************/#ifndef _SB_USE_STD_NAMESPACE#define _SB_USE_STD_NAMESPACE#endif#ifdef WIN32#ifndef UNICODE#define UNICODE#endif#ifndef _UNICODE#define _UNICODE#endif#undef HTTP_VERSION#define WIN32_LEAN_AND_MEAN#include <windows.h>#endif#include <sys/timeb.h> // for _ftime( )/ftime( )#include <WWWLib.h>#include <WWWHTTP.h>#include <WWWInit.h>#ifdef EINVAL// Conflicts with OS definition#undef EINVAL#endif#include "VXIvalue.h"#include "VXIinet.h"#include "VXItrd.h"#include "SBinetLog.h"#include "SBinetURL.h"#include "SBinetStream.h"#include "SBinetChannel.h"#include "SBinetValidator.h"#include "SBinetCacheLock.h"#include "HTCache.h" /* Implemented here */#include "HTAncMan.h"#include "HTAnchor.h"#include "HTReq.h"#include "HTReqMan.h"#ifdef WIN32/* Suppress/disable warnings */#pragma warning(4 : 4706) /* Assignment within conditional expression (for Libwww HTList_[...]( ) macros) */#endif#define INET_INFO_HTTP_STATUS L"inet.httpStatus"extern "C" {#include "SBHTStream.h"}#ifndef WIN32#define Sleep(x) usleep(1000*(x))#endif #define MAX_CHUNK_SIZE (10 * 1024 * 1024)HTChunk*SBinetHttpStream::Get(SBinetURL* url, VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo){ /* Setup to read to chunk for now. Non-optimal in that chunk is size limited Also, we must wait for entire download to happen. Can we get a callback when header is complete?? Note: This performs Web transaction in this thread until something would block, then returns, and rest of download is done in event thread. Since we are waiting here anyway, we could actually use blocking IO, but we hope to fix all in future. Tried to make a Stream class that would return WOULD_BLOCK when full (instead of failing as Chunks do). However, there seems to be no mechanism in libwww for dealing with this. The result was deadlock as the system ceased to get events, behavior is worse if the doc was in cache. For now we are just going to use the libww chunk class and live with the size limitation. Also, as a consequence, Open will not return until the entire doc is downloaded into memory...bogus, but that seems to be the way libwww works. */ HTRequest_setMethod(m_request,METHOD_GET); url->AppendQueryArgs(m_queryArgs); const char* absolute_url = url->GetAbsoluteNarrow(); HTAnchor* anchor = HTAnchor_findAddress(absolute_url); // Need to do this for CacheValid HTRequest_setAnchor(m_request,anchor); /* * get lock for anchor */ m_lock = SBinetCacheLockTable::FindCacheLock(anchor); if(m_lock == NULL){ // Should never fail Error (217, NULL); return(NULL); } /* * lock anchor -- Must unlock libwww while waiting to avoid deadlock */ SBinetInterface::UnlockLibwww( ); m_lock->GetReadLock(m_request); SBinetInterface::LockLibwww( ); /* * This test used to be part of ill-fated multiple-reader scheme, now only informative * Note: Change printfs to Log when satisfied. if(CacheValid(m_request)){ printf("Request in cache"); } else{ printf("Request NOT in cache\n"); } */ /* * The actual call */ m_chunk = NULL; HTStream * target = SBHTStream(m_request, &m_chunk, MAX_CHUNK_SIZE); HTRequest_setOutputStream(m_request, target); if(HTLoadAnchor((HTAnchor*)anchor, m_request) != YES){ HTChunk_delete(m_chunk); m_chunk = NULL; } return(m_chunk);}/* * POST simple form data. Don't know how to combine Form data * and audio in multipart POST */HTChunk*SBinetHttpStream::PostMulti(SBinetURL* url, VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo){ /* Get an anchor object for the URI */ const char* absolute_url = url->GetAbsoluteNarrow(); HTAnchor* anchor = HTAnchor_findAddress(absolute_url); /* * get lock for anchor */ m_lock = SBinetCacheLockTable::FindCacheLock(anchor); if(m_lock == NULL){ // Should never fail Error (217, NULL); return(NULL); } /* * lock anchor -- Must unlock libwww while waiting to avoid deadlock */ SBinetInterface::UnlockLibwww( ); m_lock->GetReadLock(m_request); SBinetInterface::LockLibwww( ); /* * Set up Post (copied from HTPostFormAnchorToChunk */ // get doc for query args VXIulong doclen = 0; const char* doc = url->QueryArgsToMultipart(m_queryArgs,&doclen); HTUserProfile * up = HTRequest_userProfile(m_request); char * tmpfile = HTGetTmpFileName(HTUserProfile_tmp(up)); char * tmpurl = HTParse(tmpfile, "file:", PARSE_ALL); /* ** Now create a new anchor for the post data and set up ** the rest of the metainformation we know about this anchor. The ** tmp anchor may actually already exist from previous postings. */ HTParentAnchor* postanchor = (HTParentAnchor *) HTAnchor_findAddress(tmpurl); HTAnchor_clearHeader(postanchor); // Who frees doc??? HTAnchor_setDocument(postanchor, (void *) doc); HTAnchor_setLength(postanchor, doclen); HTAnchor_setFormat(postanchor, HTAtom_for(SB_MULTIPART)); HTStream * target = SBHTStream(m_request, &m_chunk, MAX_CHUNK_SIZE); HTRequest_setOutputStream(m_request, target); // I think this does the right thing if(HTPostAnchor(postanchor,anchor,m_request) == YES){ HT_FREE(tmpfile); HT_FREE(tmpurl); } else{ HTChunk_delete(m_chunk); m_chunk = NULL; } return(m_chunk);}/* * POST simple form data. Don't know how to combine Form data and audio in multipart POST */HTChunk*SBinetHttpStream::Post(SBinetURL* url, VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo){ /* Get an anchor object for the URI */ const char* absolute_url = url->GetAbsoluteNarrow(); HTAnchor* anchor = HTAnchor_findAddress(absolute_url); // HTRequest_setOutputFormat( m_request, HTAtom_for( m_submitMimeType )); // If we are a multipart MIME (ie sending audio) branch to special POST if(url->NeedMultipart(m_queryArgs)){ return(PostMulti(url,flags,properties,streamInfo)); } HTAssocList* arglist = url->QueryArgsToHtList(m_queryArgs); /* * get lock for anchor */ m_lock = SBinetCacheLockTable::FindCacheLock(anchor); if(m_lock == NULL){ // Should never fail Error (217, NULL); return(NULL); } /* * lock anchor -- Must unlock libwww while waiting to avoid deadlock */ SBinetInterface::UnlockLibwww( ); m_lock->GetReadLock(m_request); SBinetInterface::LockLibwww( ); /* Post the data and get the result in a chunk */ m_chunk = NULL; HTStream * target = SBHTStream(m_request, &m_chunk, MAX_CHUNK_SIZE); HTRequest_setOutputStream(m_request, target); if(arglist == NULL){ // NULL arglist, converting to GET // PostFormAnchor will bomb, use LoadAnchor instead if(HTLoadAnchor(anchor, m_request) == NO){ HTChunk_delete(m_chunk); m_chunk = NULL; } } else{ if(HTPostFormAnchor(arglist, anchor, m_request) == NULL){ HTChunk_delete(m_chunk); m_chunk = NULL; } HTAssocList_delete(arglist); } return(m_chunk);}int SBinetHttpStream::getTime(time_t *timestamp, VXIunsigned *timestampMsec){#ifdef WIN32 struct _timeb tbuf; _ftime(&tbuf); *timestamp = tbuf.time; *timestampMsec = (VXIunsigned) tbuf.millitm;#else struct timeb tbuf; ftime(&tbuf); *timestamp = tbuf.time; *timestampMsec = (VXIunsigned) tbuf.millitm;#endif return 0;}intSBinetHttpStream::checkTimeout(){ time_t currentTime; VXIunsigned currentTimeMsec; getTime( ¤tTime, ¤tTimeMsec ); long elapsedMillis = ( currentTime - m_ReferenceTime ) * 1000L + currentTimeMsec - m_ReferenceTimeMsec; if(elapsedMillis >= m_nTimeoutOpen){ return(1); } return(0);}intSBinetHttpStream::terminate_handler (HTRequest * request, HTResponse * response, void * param, int status) { /* Check for status */ SBinetHttpStream* str = (SBinetHttpStream*)param; HTParentAnchor* anc = HTRequest_anchor(request); /* we're not handling other requests */ if(str && !str->m_Done && (status != 301) && (status != 302)){ str->m_Done = 1; str->m_HttpStatus = status; } /* stop here */ return HT_OK;}VXIinetResultSBinetHttpStream::Open(VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo){ // Set up properties instance SetProperties((VXIMap*)properties); // Determine if this is a conditional open with a validator, // irrelevant if caching is disabled const VXIValue* validatorVal = NULL; if (m_iMaxAge != 0) { validatorVal = VXIMapGetProperty( properties, INET_OPEN_IF_MODIFIED ); if (validatorVal != NULL) { SBinetValidator validator(GetLog(), GetDiagBase()); if (validator.Create(validatorVal) == VXIinet_RESULT_SUCCESS) { validator.Log(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::Open"); // No need to fetch this if it has not expired, however still // have to return the validator in streamInfo if (! validator.Expired()) { if (streamInfo) { if (VXIMapSetProperty(streamInfo, INET_INFO_VALIDATOR, VXIValueClone(validatorVal)) != VXIvalue_RESULT_SUCCESS) { Error(103, NULL); return VXIinet_RESULT_OUT_OF_MEMORY; } } return VXIinet_RESULT_NOT_MODIFIED; } } } } // Set up request SBinetInterface::LockLibwww( ); getTime( &m_ReferenceTime, &m_ReferenceTimeMsec ); m_request = HTRequest_new(); m_Done = 0; m_HttpStatus = -1234; /* Store pointer so we can get at it later in callbacks */ HTRequest_setContext(m_request,(void*) this); /* We want user output: no headers or strange length stuff */ HTRequest_setOutputFormat(m_request, WWW_SOURCE); /* Close connection immediately */ HTRequest_addConnection(m_request, "close", ""); /* Add our own filter to handle termination */ HTRequest_addAfter(m_request, SBinetHttpStream::terminate_handler, NULL, this, HT_ALL, HT_FILTER_LAST,NO); SetCachingMode(); // Start request - get or post if(m_method == GET_METHOD){ m_chunk = Get(m_url,flags,properties,streamInfo); } else if(m_method == POST_METHOD){ m_chunk = Post(m_url,flags,properties,streamInfo); } SBinetInterface::UnlockLibwww( ); if(!m_chunk){ Error(218, L"%s%s%s%s", L"URL", m_url->GetAbsolute(), L"Method", (m_method == GET_METHOD) ? L"GET" : L"POST"); // clean up Close(); return(VXIinet_RESULT_FAILURE); } // Wait for completion -- common // Really should sleep on timer and wait for wakeup? Actually depends on cost of sleep/wakeup vs // a little gratuitous spinning. int sleepTime = 1; while(!m_Done){ if(checkTimeout()) { Error(228, L"%s%s%s%s%s%i", L"URL", m_url->GetAbsolute(), L"Method", (m_method == GET_METHOD) ? L"GET" : L"POST", L"Delay", m_nTimeoutOpen); Close(); return( VXIinet_RESULT_FETCH_TIMEOUT ); } Sleep(sleepTime);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -