[mapguide-commits] r7756 - in sandbox/jng/streaming_v2: Common/Foundation/System Web/src/ApacheAgent Web/src/CgiAgent Web/src/HttpHandler Web/src/IsapiAgent
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Sun Aug 11 07:41:25 PDT 2013
Author: jng
Date: 2013-08-11 07:41:25 -0700 (Sun, 11 Aug 2013)
New Revision: 7756
Added:
sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.h
Modified:
sandbox/jng/streaming_v2/Common/Foundation/System/ByteSourceImpl.h
sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.cpp
sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.h
sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheResponseHandler.cpp
sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.cpp
sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.h
sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiResponseHandler.cpp
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj.filters
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandlerBuild.cpp
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.cpp
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.h
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.cpp
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.h
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResult.h
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeatures.cpp
sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp
sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.cpp
sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.h
sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiResponseHandler.cpp
Log:
Refactor the streaming mechanism.
- Modify MgHttpReaderStreamer (and its derivatives) to work off a MgByteReader instead of a MgReader
- dllexport the ByteSourceImpl class from the Foundation library
- Implement a new MgReaderByteSourceImpl class that inherits from ByteSourceImpl. It takes a MgReader and mime type as input and provides an adapter that allows a MgReader to be streamed out as a MgByteReader.
The benefit of this approach is that if one were to implement a mapagent handler outside of CGI/ISAPI/Apache, they don't have to implement a specialized MgReader streaming class. Any HTTP operation that would return MgReader now returns a MgByteReader instead so output logic of a SELECTFEATURES or SELECTAGGREGATES operation is the same as any other MgByteReader. The only difference here is that the handler should check for a chunked response hint from the header of the MgHttpResponse and apply appropriate chunked response headers if this hint exists. The existing Apache/CGI/ISAPI handlers have been modified to check for this hint.
Modified: sandbox/jng/streaming_v2/Common/Foundation/System/ByteSourceImpl.h
===================================================================
--- sandbox/jng/streaming_v2/Common/Foundation/System/ByteSourceImpl.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Common/Foundation/System/ByteSourceImpl.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -23,7 +23,7 @@
/// \brief
/// Placeholder for various ByteSourceInfo derived classes, which supply
/// the actual access to the bytes in the source
-class ByteSourceImpl
+class MG_FOUNDATION_API ByteSourceImpl
{
public:
Modified: sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -19,8 +19,8 @@
#include "http_protocol.h"
-ApacheReaderStreamer::ApacheReaderStreamer(request_rec* rec, MgReader* reader, CREFSTRING format) :
- MgHttpReaderStreamer(reader, format), m_r(rec)
+ApacheReaderStreamer::ApacheReaderStreamer(request_rec* rec, MgByteReader* reader) :
+ MgHttpReaderStreamer(reader), m_r(rec)
{
}
Modified: sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheReaderStreamer.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -26,7 +26,7 @@
class ApacheReaderStreamer : public MgHttpReaderStreamer
{
public:
- ApacheReaderStreamer(request_rec* rec, MgReader* reader, CREFSTRING format);
+ ApacheReaderStreamer(request_rec* rec, MgByteReader* reader);
virtual ~ApacheReaderStreamer();
protected:
Modified: sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheResponseHandler.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheResponseHandler.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/ApacheAgent/ApacheResponseHandler.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -98,7 +98,6 @@
m_r->content_type = apr_pstrdup(m_r->pool, tempHeader);
}
- Ptr<MgReader> outputDataReader;
Ptr<MgByteReader> outputReader;
Ptr<MgDisposable> resultObj = result->GetResultObject();
MgDisposable* pResultObj = (MgDisposable*)resultObj;
@@ -107,22 +106,10 @@
{
outputReader = (MgByteReader*) SAFE_ADDREF(pResultObj);
}
- else if (NULL != dynamic_cast<MgFeatureReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgFeatureReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
else if (NULL != dynamic_cast<MgStringCollection*>(pResultObj))
{
outputReader = ((MgStringCollection*)pResultObj)->ToXml();
}
- else if (NULL != dynamic_cast<MgSqlDataReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgSqlDataReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
- else if (NULL != dynamic_cast<MgDataReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgDataReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
else if (NULL != dynamic_cast<MgSpatialContextReader*>(pResultObj))
{
outputReader = ((MgSpatialContextReader*)pResultObj)->ToXml();
@@ -145,25 +132,30 @@
ap_send_http_header(m_r);
ap_rwrite(utf8.c_str(), (int)utf8.length(), m_r);
}
- else if (outputDataReader != NULL)
- {
- ApacheReaderStreamer ars(m_r, outputDataReader, result->GetResultContentType());
- ars.StreamResult();
- }
else if (outputReader != NULL)
{
- INT64 outLen = outputReader->GetLength();
- sprintf(tempHeader, "%d", (INT32)outLen);
- apr_table_set(m_r->headers_out, MapAgentStrings::ContentLengthKey, tempHeader);
- ap_send_http_header(m_r);
-
- unsigned char buf[4096];
- int nBytes = outputReader->Read(buf,4096);
- while (nBytes > 0)
+ Ptr<MgHttpHeader> respHeader = response->GetHeader();
+ //Check for chunking hint
+ if (respHeader->GetHeaderValue(MgHttpResourceStrings::hrhnTransfer_Encoding) == MgHttpResourceStrings::hrhnChunked)
{
- ap_rwrite(buf, nBytes, m_r);
- nBytes = outputReader->Read(buf,4096);
+ ApacheReaderStreamer ars(m_r, outputReader);
+ ars.StreamResult();
}
+ else
+ {
+ INT64 outLen = outputReader->GetLength();
+ sprintf(tempHeader, "%d", (INT32)outLen);
+ apr_table_set(m_r->headers_out, MapAgentStrings::ContentLengthKey, tempHeader);
+ ap_send_http_header(m_r);
+
+ unsigned char buf[4096];
+ int nBytes = outputReader->Read(buf,4096);
+ while (nBytes > 0)
+ {
+ ap_rwrite(buf, nBytes, m_r);
+ nBytes = outputReader->Read(buf,4096);
+ }
+ }
}
else
{
Modified: sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -22,8 +22,8 @@
extern void DumpMessage2(const char* msg);
-CgiReaderStreamer::CgiReaderStreamer(MgReader* reader, CREFSTRING format) :
- MgHttpReaderStreamer(reader, format),
+CgiReaderStreamer::CgiReaderStreamer(MgByteReader* reader) :
+ MgHttpReaderStreamer(reader),
m_bEndOfStream(false)
{
}
Modified: sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiReaderStreamer.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -24,7 +24,7 @@
class CgiReaderStreamer : public MgHttpReaderStreamer
{
public:
- CgiReaderStreamer(MgReader* reader, CREFSTRING format);
+ CgiReaderStreamer(MgByteReader* reader);
virtual ~CgiReaderStreamer();
protected:
Modified: sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiResponseHandler.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiResponseHandler.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/CgiAgent/CgiResponseHandler.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -102,7 +102,6 @@
printf(MapAgentStrings::ContentTypeHeader, MapAgentStrings::TextPlain, MapAgentStrings::Utf8Text);
}
- Ptr<MgReader> outputDataReader;
Ptr<MgByteReader> outputReader;
Ptr<MgDisposable> resultObj = result->GetResultObject();
MgDisposable* pResultObj = (MgDisposable*)resultObj;
@@ -111,22 +110,10 @@
{
outputReader = (MgByteReader*) SAFE_ADDREF(pResultObj);
}
- else if (NULL != dynamic_cast<MgFeatureReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgFeatureReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
else if (NULL != dynamic_cast<MgStringCollection*>(pResultObj))
{
outputReader = ((MgStringCollection*)pResultObj)->ToXml();
}
- else if (NULL != dynamic_cast<MgSqlDataReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgSqlDataReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
- else if (NULL != dynamic_cast<MgDataReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgDataReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
else if (NULL != dynamic_cast<MgSpatialContextReader*>(pResultObj))
{
outputReader = ((MgSpatialContextReader*)pResultObj)->ToXml();
@@ -146,23 +133,28 @@
printf(MapAgentStrings::ContentLengthHeader, utf8.length());
printf("\r\n%s",utf8.c_str());
}
- else if (outputDataReader != NULL)
- {
- CgiReaderStreamer crs(outputDataReader, result->GetResultContentType());
- crs.StreamResult();
- }
else if (outputReader != NULL)
{
- INT64 outLen = outputReader->GetLength();
- printf(MapAgentStrings::ContentLengthHeader,(INT32)outLen);
- printf("\r\n");
- unsigned char buf[4096];
- int nBytes = outputReader->Read(buf,4096);
- while (nBytes > 0)
+ Ptr<MgHttpHeader> respHeader = response->GetHeader();
+ //Check for chunking hint
+ if (respHeader->GetHeaderValue(MgHttpResourceStrings::hrhnTransfer_Encoding) == MgHttpResourceStrings::hrhnChunked)
{
- fwrite(buf, 1, nBytes, stdout);
- nBytes = outputReader->Read(buf,4096);
+ CgiReaderStreamer crs(outputReader);
+ crs.StreamResult();
}
+ else
+ {
+ INT64 outLen = outputReader->GetLength();
+ printf(MapAgentStrings::ContentLengthHeader,(INT32)outLen);
+ printf("\r\n");
+ unsigned char buf[4096];
+ int nBytes = outputReader->Read(buf,4096);
+ while (nBytes > 0)
+ {
+ fwrite(buf, 1, nBytes, stdout);
+ nBytes = outputReader->Read(buf,4096);
+ }
+ }
}
else
{
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj 2013-08-11 14:41:25 UTC (rev 7756)
@@ -712,6 +712,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
+ <ClCompile Include="ReaderByteSourceImpl.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </ClCompile>
<ClCompile Include="WfsFeatureDefinitions.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1031,6 +1037,7 @@
<ClInclude Include="OgcWmsException.h" />
<ClInclude Include="OgcWmsServer.h" />
<ClInclude Include="HttpReaderStreamer.h" />
+ <ClInclude Include="ReaderByteSourceImpl.h" />
<ClInclude Include="ResponseStream.h" />
<ClInclude Include="Stream.h" />
<ClInclude Include="StringStream.h" />
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj.filters
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj.filters 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandler.vcxproj.filters 2013-08-11 14:41:25 UTC (rev 7756)
@@ -37,6 +37,9 @@
<Filter Include="Web Applications">
<UniqueIdentifier>{e21c5925-6c01-4fe4-89d2-1e95e2b3d79e}</UniqueIdentifier>
</Filter>
+ <Filter Include="Byte Source Adapters">
+ <UniqueIdentifier>{0f2e34d9-18f7-49af-b11f-8d3c874192ec}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="HttpApplyResourcePackage.cpp">
@@ -383,6 +386,9 @@
<ClCompile Include="HttpCreateRuntimeMap.cpp">
<Filter>Mapping Service</Filter>
</ClCompile>
+ <ClCompile Include="ReaderByteSourceImpl.cpp">
+ <Filter>Byte Source Adapters</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="HttpApplyResourcePackage.h">
@@ -754,6 +760,9 @@
<ClInclude Include="HttpCreateRuntimeMap.h">
<Filter>Mapping Service</Filter>
</ClInclude>
+ <ClInclude Include="ReaderByteSourceImpl.h">
+ <Filter>Byte Source Adapters</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HttpHandler.rc" />
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandlerBuild.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandlerBuild.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpHandlerBuild.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -125,6 +125,8 @@
#include "HttpEnumerateUnmanagedData.cpp"
#include "WmsMapUtil.cpp"
+#include "ReaderByteSourceImpl.cpp"
+
// JSON conversion files
#include "XmlJsonConvert.cpp"
#include "JsonDoc.cpp"
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -18,11 +18,11 @@
#include "HttpHandler.h"
#include "XmlJsonConvert.h"
+#define CHUNK_SIZE 8192
-MgHttpReaderStreamer::MgHttpReaderStreamer(MgReader* reader, CREFSTRING format)
+MgHttpReaderStreamer::MgHttpReaderStreamer(MgByteReader* reader)
{
m_reader = SAFE_ADDREF(reader);
- m_format = format;
}
@@ -53,126 +53,13 @@
SetChunkedEncoding();
- if (m_format == MgMimeType::Json)
+ unsigned char buf[CHUNK_SIZE] = { 0 };
+ INT32 read = m_reader->Read(buf, CHUNK_SIZE);
+ while (read > 0)
{
- std::string buf;
- std::string jsonbuf;
-
- //How this looks:
- //
- // { //outer JSON start
- // "ResponseElementName": //root element name
- // { //root JSON property start
- // <header JSON pair>,
- // "BodyElementName":[ //body JSON array start
- //
- jsonbuf = "{\"";
- jsonbuf += m_reader->GetResponseElementName();
- jsonbuf += "\":{";
- m_reader->HeaderToStringUtf8(buf);
- std::string jsonbuf2;
- ToJson(buf, jsonbuf2);
- //This will have redudant outer { }, so strip them
- jsonbuf2.erase(0, 1);
- jsonbuf2.erase(jsonbuf2.length() - 2, 1);
- //HACK: To match the original output, we have to array-ify this object (crazy? yes!)
- //
- //We currently have something like this
- //
- // "HeaderElementName":{
- // <prop1>:<val1>,
- // <prop2>:<val2>
- // }
- //
- //We have to change it to this
- //
- // "HeaderElementName":[{
- // <prop1>:<val1>,
- // <prop2>:<val2>
- // }]
-
- //Find first instance of ": and insert [ after it. We use ": because a feature
- //reader puts out xs:schema as the header element name
- jsonbuf2.insert(jsonbuf2.find("\":") + 2, "[");
- //Append ] to the end
- jsonbuf2.append("]");
-
- jsonbuf += jsonbuf2;
- jsonbuf += ",\"";
- jsonbuf += m_reader->GetBodyElementName();
- jsonbuf += "\":[";
-
- WriteChunk(jsonbuf.c_str(), jsonbuf.length());
-
- bool bNext = m_reader->ReadNext();
- while(bNext)
- {
- buf.clear();
- jsonbuf.clear();
- m_reader->CurrentToStringUtf8(buf);
- //The body is a valid full XML element, so no need for gymnastics like its
- //surrounding elements
- ToJson(buf, jsonbuf);
-
- //Strip outer { }
- jsonbuf.erase(0, 1);
- jsonbuf.erase(jsonbuf.length() - 2, 1);
- //HACK: Same as the header, this needs to be array-ified to match the old output
- //
- //Find first instance of ": and insert [ after it.
- jsonbuf.insert(jsonbuf.find("\":") + 2, "[");
- //Append ] to the end
- jsonbuf.append("]");
- //Put back in outer { }
- jsonbuf = "{" + jsonbuf;
- jsonbuf += "}";
-
- bNext = m_reader->ReadNext();
- if (bNext)
- jsonbuf += ",";
- WriteChunk(jsonbuf.c_str(), jsonbuf.length());
- }
-
- buf.clear();
- jsonbuf.clear();
-
- // How this looks:
- // ] //End of body JSON array
- // } //End of root JSON property
- // } //End of outer JSON
- jsonbuf = "]}}";
- WriteChunk(jsonbuf.c_str(), jsonbuf.length());
+ WriteChunk((char*)buf, read);
+ read = m_reader->Read(buf, CHUNK_SIZE);
}
- else if (m_format == MgMimeType::Xml)
- {
- std::string buf;
- m_reader->ResponseStartUtf8(buf);
- m_reader->HeaderToStringUtf8(buf);
- m_reader->BodyStartUtf8(buf);
- WriteChunk(buf.c_str(), buf.length());
-
- while(m_reader->ReadNext())
- {
- buf.clear();
- m_reader->CurrentToStringUtf8(buf);
- WriteChunk(buf.c_str(), buf.length());
- }
-
- buf.clear();
-
- m_reader->BodyEndUtf8(buf);
- m_reader->ResponseEndUtf8(buf);
-
- WriteChunk(buf.c_str(), buf.length());
- }
-
MG_CATCH_AND_THROW(L"MgHttpReaderStreamer.StreamResult");
-}
-
-
-void MgHttpReaderStreamer::ToJson(string& xmlString, string& jsonString)
-{
- MgXmlJsonConvert convert;
- convert.ToJson(xmlString, jsonString);
-}
+}
\ No newline at end of file
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpReaderStreamer.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -29,16 +29,14 @@
virtual ~MgHttpReaderStreamer();
protected:
- MgHttpReaderStreamer(MgReader* reader, CREFSTRING format);
+ MgHttpReaderStreamer(MgByteReader* reader);
virtual void SetChunkedEncoding();
virtual void WriteChunk(const char* str, size_t length);
virtual void Dispose() { delete this; }
virtual void EndStream();
private:
- void ToJson(string& xmlString, string& jsonString);
- Ptr<MgReader> m_reader;
- STRING m_format;
+ Ptr<MgByteReader> m_reader;
};
#endif
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -37,6 +37,8 @@
const STRING MgHttpResourceStrings::hrhnPublic = L"Public";
const STRING MgHttpResourceStrings::hrhnContent_Length = L"Content-Length";
const STRING MgHttpResourceStrings::hrhnContent_Type = L"Content-Type";
+const STRING MgHttpResourceStrings::hrhnTransfer_Encoding = L"Transfer-Encoding";
+const STRING MgHttpResourceStrings::hrhnChunked = L"chunked";
const STRING MgHttpResourceStrings::hrhnContent_Transfer_Encoding = L"Content-Transfer-Encoding";
const STRING MgHttpResourceStrings::hrhnContent_Encoding = L"Content-Encoding";
const STRING MgHttpResourceStrings::hrhnDate = L"Date";
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResourceStrings.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -40,6 +40,8 @@
static const STRING hrhnPublic;
static const STRING hrhnContent_Length;
static const STRING hrhnContent_Type;
+ static const STRING hrhnTransfer_Encoding;
+ static const STRING hrhnChunked;
static const STRING hrhnContent_Transfer_Encoding;
static const STRING hrhnContent_Encoding;
static const STRING hrhnDate;
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResult.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResult.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpResult.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -152,6 +152,8 @@
MgHttpResult(MgDisposable* resultObject);
+ void SetChunked(bool bChunked);
+
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Sets the error information based on a Mg exception.
@@ -182,6 +184,7 @@
STRING m_DetailedMessage;
STRING m_HttpStatusMessage;
STRING m_contentType;
+ bool m_chunkResult;
CLASS_ID:
static const INT32 m_cls_id = HttpHandler_MapAgent_HttpResult;
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeatures.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeatures.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeatures.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -17,6 +17,7 @@
#include "HttpHandler.h"
#include "HttpSelectFeatures.h"
+#include "ReaderByteSourceImpl.h"
HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpSelectFeatures)
@@ -104,9 +105,17 @@
}
Ptr<MgFeatureReader> featureReader = service->SelectFeatures(&resId, m_className, qryOptions);
- //HACK-ish: We're passing conversion responsibility to the caller (agent), so we store the
- //originally requested format so the caller can determine if conversion is required
- hResult->SetResultObject(featureReader, m_responseFormat);
+ //MgByteSource owns this and will clean it up when done
+ ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(featureReader, m_responseFormat);
+ Ptr<MgByteSource> byteSource = new MgByteSource(bsImpl);
+ Ptr<MgByteReader> byteReader = byteSource->GetReader();
+ hResult->SetResultObject(byteReader, m_responseFormat);
+
+ Ptr<MgHttpHeader> respHeader = hResponse.GetHeader();
+
+ //This is the "hint" to chunk the MgByteReader content
+ respHeader->AddHeader(MgHttpResourceStrings::hrhnTransfer_Encoding, MgHttpResourceStrings::hrhnChunked);
+
MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpSelectFeatures.Execute")
}
Modified: sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -17,6 +17,7 @@
#include "HttpHandler.h"
#include "HttpSelectFeaturesSpatially.h"
+#include "ReaderByteSourceImpl.h"
HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpSelectFeaturesSpatially)
@@ -114,9 +115,17 @@
}
Ptr<MgDataReader> dataReader = service->SelectAggregate(&resId, m_className, qryOptions);
- //HACK-ish: We're passing conversion responsibility to the caller (agent), so we store the
- //originally requested format so the caller can determine if conversion is required
- hResult->SetResultObject(dataReader, m_responseFormat);
+ //MgByteSource owns this and will clean it up when done
+ ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(dataReader, m_responseFormat);
+ Ptr<MgByteSource> byteSource = new MgByteSource(bsImpl);
+ Ptr<MgByteReader> byteReader = byteSource->GetReader();
+ hResult->SetResultObject(byteReader, m_responseFormat);
+
+ Ptr<MgHttpHeader> respHeader = hResponse.GetHeader();
+
+ //This is the "hint" to chunk the MgByteReader content
+ respHeader->AddHeader(MgHttpResourceStrings::hrhnTransfer_Encoding, MgHttpResourceStrings::hrhnChunked);
+
MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpSelectFeaturesSpatially.Execute")
}
Added: sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.cpp (rev 0)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -0,0 +1,274 @@
+#include "ReaderByteSourceImpl.h"
+#include "PlatformBase.h"
+
+MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format)
+{
+ m_reader = SAFE_ADDREF(reader);
+ m_format = format;
+ m_buf.reserve(8192);
+ m_bufOffset = -1;
+ m_bReadHeader = false;
+ m_bInternalReaderHasMore = true;
+ m_bFirstRecord = true;
+}
+
+MgReaderByteSourceImpl::~MgReaderByteSourceImpl()
+{
+ m_reader = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Reads a buffer
+///
+/// \param buffer
+/// A buffer receiving the data.
+/// \param length
+/// Maximum number of bytes to read
+///
+/// \return
+/// Actual number of bytes put in the buffer. 0 means end of bytes
+///
+INT32 MgReaderByteSourceImpl::Read(BYTE_ARRAY_OUT buffer, INT32 length)
+{
+ INT32 ret = 0;
+
+ bool bAdvanceReader = false;
+ std::string buf;
+ std::string jsonbuf;
+
+ //Haven't read header, pre-fill this buffer
+ if (!m_bReadHeader)
+ {
+ if (m_format == MgMimeType::Json)
+ {
+ //How this looks:
+ //
+ // { //outer JSON start
+ // "ResponseElementName": //root element name
+ // { //root JSON property start
+ // <header JSON pair>,
+ // "BodyElementName":[ //body JSON array start
+ //
+ jsonbuf = "{\"";
+ jsonbuf += m_reader->GetResponseElementName();
+ jsonbuf += "\":{";
+ m_reader->HeaderToStringUtf8(buf);
+ std::string jsonbuf2;
+ MgXmlJsonConvert convert;
+ convert.ToJson(buf, jsonbuf2);
+ //This will have redudant outer { }, so strip them
+ jsonbuf2.erase(0, 1);
+ jsonbuf2.erase(jsonbuf2.length() - 2, 1);
+ //HACK: To match the original output, we have to array-ify this object (crazy? yes!)
+ //
+ //We currently have something like this
+ //
+ // "HeaderElementName":{
+ // <prop1>:<val1>,
+ // <prop2>:<val2>
+ // }
+ //
+ //We have to change it to this
+ //
+ // "HeaderElementName":[{
+ // <prop1>:<val1>,
+ // <prop2>:<val2>
+ // }]
+
+ //Find first instance of ": and insert [ after it. We use ": because a feature
+ //reader puts out xs:schema as the header element name
+ jsonbuf2.insert(jsonbuf2.find("\":") + 2, "[");
+ //Append ] to the end
+ jsonbuf2.append("]");
+ jsonbuf += jsonbuf2;
+ jsonbuf += ",\"";
+ jsonbuf += m_reader->GetBodyElementName();
+ jsonbuf += "\":[";
+
+ m_buf += jsonbuf;
+ m_bReadHeader = true;
+ }
+ else if (m_format == MgMimeType::Xml)
+ {
+ m_reader->ResponseStartUtf8(m_buf);
+#ifdef _DEBUG
+ m_buf += "<!-- BEGIN HEADER -->\n";
+#endif
+ m_reader->HeaderToStringUtf8(m_buf);
+#ifdef _DEBUG
+ m_buf += "<!-- END HEADER -->\n";
+ m_buf += "<!-- BEGIN BODY -->\n";
+#endif
+ m_reader->BodyStartUtf8(m_buf);
+ m_bReadHeader = true;
+ }
+ }
+
+ INT32 maxIndex = m_buf.length() - 1;
+ //We have an internal buffer. Clear this out first
+ if (m_bufOffset < maxIndex)
+ {
+ INT32 read = ReadInternalBuffer(buffer, ret, length);
+ ret += read;
+ }
+
+ //If we've filled the whole internal buffer and the requested length is still
+ //bigger, we're good to advance to the next feature/record
+ if (ret < length)
+ bAdvanceReader = true;
+ else //Filled up to requested length
+ return ret;
+
+ if (m_bInternalReaderHasMore && bAdvanceReader)
+ {
+ m_bInternalReaderHasMore = m_reader->ReadNext();
+ if (m_bInternalReaderHasMore)
+ {
+ if (m_format == MgMimeType::Json)
+ {
+ m_reader->CurrentToStringUtf8(buf);
+ //The body is a valid full XML element, so no need for gymnastics like its
+ //surrounding elements
+ MgXmlJsonConvert convert;
+ convert.ToJson(buf, jsonbuf);
+
+ //Strip outer { }
+ jsonbuf.erase(0, 1);
+ jsonbuf.erase(jsonbuf.length() - 2, 1);
+ //HACK: Same as the header, this needs to be array-ified to match the old output
+ //
+ //Find first instance of ": and insert [ after it.
+ jsonbuf.insert(jsonbuf.find("\":") + 2, "[");
+ //Append ] to the end
+ jsonbuf.append("]");
+ //Put back in outer { }
+ jsonbuf = "{" + jsonbuf;
+ jsonbuf += "}";
+
+ if (!m_bFirstRecord)
+ {
+ m_buf += ",";
+ }
+ else
+ {
+ m_bFirstRecord = false;
+ }
+
+ m_buf += jsonbuf;
+ }
+ else if (m_format == MgMimeType::Xml)
+ {
+#ifdef _DEBUG
+ m_buf += "<!-- BEGIN RECORD -->\n";
+#endif
+ m_reader->CurrentToStringUtf8(m_buf);
+#ifdef _DEBUG
+ m_buf += "<!-- END RECORD -->\n";
+#endif
+ }
+ }
+ else //End of reader
+ {
+ if (m_format == MgMimeType::Json)
+ {
+#ifdef _DEBUG
+ //m_buf += "//END BODY\n";
+#endif
+ // How this looks:
+ // ] //End of body JSON array
+ // } //End of root JSON property
+ // } //End of outer JSON
+ m_buf += "]}}";
+ }
+ else if (m_format == MgMimeType::Xml)
+ {
+ m_reader->BodyEndUtf8(m_buf);
+#ifdef _DEBUG
+ m_buf += "<!-- END BODY -->\n";
+#endif
+ m_reader->ResponseEndUtf8(m_buf);
+ }
+ }
+ }
+
+ //Clear out however many remaining content up to the requested
+ //length
+ maxIndex = m_buf.length() - 1;
+ if (m_bufOffset < maxIndex)
+ {
+ INT32 remaining = length - ret;
+ if (remaining > 0)
+ {
+ INT32 read = ReadInternalBuffer(buffer, ret, remaining);
+ ret += read;
+ }
+ }
+
+ return ret;
+}
+
+INT32 MgReaderByteSourceImpl::ReadInternalBuffer(BYTE_ARRAY_OUT buffer, INT32 fromIndex, INT32 length)
+{
+ INT32 ret = 0;
+ while (ret < length)
+ {
+ m_bufOffset++;
+ INT32 maxIndex = m_buf.length() - 1;
+ if (m_bufOffset <= maxIndex)
+ {
+ buffer[fromIndex + ret] = m_buf[m_bufOffset];
+ ret++;
+ }
+ else //End of internal buffer. Reset offset
+ {
+ m_buf.clear();
+ m_bufOffset = -1;
+ break;
+ }
+ }
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Returns the remaining length of the byte source. This length is
+/// adjusted for previous reads. If the returned length is zero
+/// then the underlying source may be a streaming format and the length
+/// is not known.
+///
+/// \return
+/// Remaining length of the byte source
+///
+INT64 MgReaderByteSourceImpl::GetLength()
+{
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Determines if the source is rewindable.
+///
+/// \return
+/// true if the source is rewindable, false otherwise.
+///
+bool MgReaderByteSourceImpl::IsRewindable()
+{
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Rewinds to the start of the source. Depending on the source of
+/// the reader, Rewind may not be supported. Readers sourced from
+/// true streams cannot be rewound.
+///
+/// \return
+/// Nothing
+///
+/// \exception MgInvalidOperationException if source cannot be rewound
+///
+void MgReaderByteSourceImpl::Rewind()
+{
+ throw new MgInvalidOperationException(L"MgReaderByteSourceImpl.Rewind", __LINE__, __WFILE__, NULL, L"", NULL);
+}
\ No newline at end of file
Added: sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.h (rev 0)
+++ sandbox/jng/streaming_v2/Web/src/HttpHandler/ReaderByteSourceImpl.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -0,0 +1,80 @@
+#ifndef READER_BYTE_SOURCE_IMPL
+#define READER_BYTE_SOURCE_IMPL
+
+#include "Foundation.h"
+#include "XmlJsonConvert.h"
+
+class MgReader;
+
+// MgReaderByteSourceImpl provides an adapter layer to MgReader
+// objects, allowing them to be streamed/iterated with a MgByteReader
+class MG_MAPAGENT_API MgReaderByteSourceImpl : public ByteSourceImpl
+{
+ DECLARE_CLASSNAME(MgReaderByteSourceImpl)
+
+public:
+ MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format);
+ virtual ~MgReaderByteSourceImpl();
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// \brief
+ /// Reads a buffer
+ ///
+ /// \param buffer
+ /// A buffer receiving the data.
+ /// \param length
+ /// Maximum number of bytes to read
+ ///
+ /// \return
+ /// Actual number of bytes put in the buffer. 0 means end of bytes
+ ///
+ virtual INT32 Read(BYTE_ARRAY_OUT buffer, INT32 length);
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// \brief
+ /// Returns the remaining length of the byte source. This length is
+ /// adjusted for previous reads. If the returned length is zero
+ /// then the underlying source may be a streaming format and the length
+ /// is not known.
+ ///
+ /// \return
+ /// Remaining length of the byte source
+ ///
+ virtual INT64 GetLength();
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// \brief
+ /// Determines if the source is rewindable.
+ ///
+ /// \return
+ /// true if the source is rewindable, false otherwise.
+ ///
+ virtual bool IsRewindable();
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// \brief
+ /// Rewinds to the start of the source. Depending on the source of
+ /// the reader, Rewind may not be supported. Readers sourced from
+ /// true streams cannot be rewound.
+ ///
+ /// \return
+ /// Nothing
+ ///
+ /// \exception MgInvalidOperationException if source cannot be rewound
+ ///
+ virtual void Rewind();
+
+private:
+ INT32 ReadInternalBuffer(BYTE_ARRAY_OUT buffer, INT32 fromIndex, INT32 length);
+
+ Ptr<MgReader> m_reader;
+ STRING m_format;
+ bool m_bReadHeader;
+ bool m_bInternalReaderHasMore;
+ bool m_bFirstRecord;
+
+ std::string m_buf;
+ INT32 m_bufOffset;
+};
+
+#endif
\ No newline at end of file
Modified: sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -3,8 +3,8 @@
#include "IsapiReaderStreamer.h"
#include "MapAgentStrings.h"
-IsapiReaderStreamer::IsapiReaderStreamer(EXTENSION_CONTROL_BLOCK* rec, const std::string& sResponseHeader, MgReader* reader, CREFSTRING format) :
- MgHttpReaderStreamer(reader, format),
+IsapiReaderStreamer::IsapiReaderStreamer(EXTENSION_CONTROL_BLOCK* rec, const std::string& sResponseHeader, MgByteReader* reader) :
+ MgHttpReaderStreamer(reader),
m_pECB(rec),
m_sResponseHeader(sResponseHeader),
m_bEndOfStream(false)
Modified: sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.h
===================================================================
--- sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.h 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiReaderStreamer.h 2013-08-11 14:41:25 UTC (rev 7756)
@@ -23,7 +23,7 @@
class IsapiReaderStreamer : public MgHttpReaderStreamer
{
public:
- IsapiReaderStreamer(EXTENSION_CONTROL_BLOCK* rec, const std::string& sResponseHeader, MgReader* reader, CREFSTRING format);
+ IsapiReaderStreamer(EXTENSION_CONTROL_BLOCK* rec, const std::string& sResponseHeader, MgByteReader* reader);
virtual ~IsapiReaderStreamer();
protected:
Modified: sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiResponseHandler.cpp
===================================================================
--- sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiResponseHandler.cpp 2013-08-09 16:16:41 UTC (rev 7755)
+++ sandbox/jng/streaming_v2/Web/src/IsapiAgent/IsapiResponseHandler.cpp 2013-08-11 14:41:25 UTC (rev 7756)
@@ -103,7 +103,6 @@
sResponseHeader.append(tempHeader);
}
- Ptr<MgReader> outputDataReader;
Ptr<MgByteReader> outputReader;
Ptr<MgDisposable> resultObj = result->GetResultObject();
MgDisposable* pResultObj = (MgDisposable*)resultObj;
@@ -112,22 +111,10 @@
{
outputReader = (MgByteReader*) SAFE_ADDREF(pResultObj);
}
- else if (NULL != dynamic_cast<MgFeatureReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgFeatureReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
else if (NULL != dynamic_cast<MgStringCollection*>(pResultObj))
{
outputReader = ((MgStringCollection*)pResultObj)->ToXml();
}
- else if (NULL != dynamic_cast<MgSqlDataReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgSqlDataReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
- else if (NULL != dynamic_cast<MgDataReader*>(pResultObj))
- {
- outputDataReader = SAFE_ADDREF((MgDataReader*)pResultObj); //Need to AddRef because there's now 2 references on this pointer
- }
else if (NULL != dynamic_cast<MgSpatialContextReader*>(pResultObj))
{
outputReader = ((MgSpatialContextReader*)pResultObj)->ToXml();
@@ -153,28 +140,33 @@
DWORD dwBufLen = (DWORD)utf8.length();
m_pECB->WriteClient(m_pECB->ConnID, (LPVOID)utf8.c_str(), &dwBufLen, 0);
}
- else if (outputDataReader != NULL)
- {
- IsapiReaderStreamer irs(m_pECB, sResponseHeader, outputDataReader, result->GetResultContentType());
- irs.StreamResult();
- }
else if (outputReader != NULL)
{
- INT64 outLen = outputReader->GetLength();
- sprintf(tempHeader, MapAgentStrings::ContentLengthHeader, (INT32)outLen);
- sResponseHeader.append(tempHeader);
- sResponseHeader.append(MapAgentStrings::CrLf);
- WriteHeader(sResponseHeader.c_str());
-
- unsigned char buf[4096];
- DWORD dwSize;
- int nBytes = outputReader->Read(buf,4096);
- while (nBytes > 0)
+ Ptr<MgHttpHeader> respHeader = response->GetHeader();
+ //Check for chunking hint
+ if (respHeader->GetHeaderValue(MgHttpResourceStrings::hrhnTransfer_Encoding) == MgHttpResourceStrings::hrhnChunked)
{
- dwSize = nBytes;
- m_pECB->WriteClient(m_pECB->ConnID, buf, &dwSize, 0);
- nBytes = outputReader->Read(buf,4096);
+ IsapiReaderStreamer irs(m_pECB, sResponseHeader, outputReader);
+ irs.StreamResult();
}
+ else
+ {
+ INT64 outLen = outputReader->GetLength();
+ sprintf(tempHeader, MapAgentStrings::ContentLengthHeader, (INT32)outLen);
+ sResponseHeader.append(tempHeader);
+ sResponseHeader.append(MapAgentStrings::CrLf);
+ WriteHeader(sResponseHeader.c_str());
+
+ unsigned char buf[4096];
+ DWORD dwSize;
+ int nBytes = outputReader->Read(buf,4096);
+ while (nBytes > 0)
+ {
+ dwSize = nBytes;
+ m_pECB->WriteClient(m_pECB->ConnID, buf, &dwSize, 0);
+ nBytes = outputReader->Read(buf,4096);
+ }
+ }
}
else
{
More information about the mapguide-commits
mailing list