DCL 4.0
Loading...
Searching...
No Matches
HttpServletEx.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#if __DCL_WINDOWS
4 #include <windows.h>
5#else
6 #include <pthread.h>
7#endif
8
9#include <dcl/Object.h>
10
11#if __DCL_HAVE_ALLOC_DEBUG
12#undef __DCL_ALLOC_LEVEL
13#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
14#endif
15
16#include <dcl/Numeric.h>
17#ifdef __DCL_DEBUG
18#include <dcl/Thread.h>
19#endif
20#include <dcl/Files.h>
21#if 0
23#endif
24#include <dcl/HttpStream.h>
25#include <dcl/HttpServletEx.h>
26#include <dcl/StringWriter.h>
27#include <dcl/Charset.h>
30
31#if __DCL_DEBUG
32#undef __THIS_FILE__
33static const char_t* __THIS_FILE__ = __T("dcl/HttpServletEx.cpp");
34#endif
35
36__DCL_BEGIN_NAMESPACE
37
39
41 const DCL_HTTP_SERVER_API* _SAPI,
42 const DCL_HTTP_SERVLET_CONTEXT* _context,
43 const String& _tempPath
44 )
45 : HttpServletContext(_SAPI, _context), __formFileMap(_tempPath)
46{
47}
48
52
54 size_t nMaxContentLength
55 ) __DCL_THROWS1(FormDataException*)
56{
57 if (__context->pszQueryString)
59 ByteString(__context->pszQueryString),
60 __queryMap
61 );
62
63 HttpCookieDecoder::decode(getHttpHeader("Cookie"), __cookieMap);
64
65 if (methodNo() == HTTP_METHOD_POST) {
66 addHeader(HttpHeader(L"Cache-Control", L"no-cache"));
67
68 size_t nLength = contentLength();
69 if (nLength && (nMaxContentLength == 0 || nLength <= nMaxContentLength)) {
71 __context->pszContentType)) {
72 String str;
73 ByteBuffer* buf = ByteBuffer::create(nLength);
74 try {
75 size_t nRead = read(buf->data(), nLength);
76 buf->__dataLength = nRead;
77 *(buf->data() + buf->__dataLength) = L'\0';
78 ByteString s = buf;
79 buf->release();
80 __DCL_ASSERT(nRead == nLength);
81
83 }
84 catch(IOException* e) {
85 buf->release();
86 throw e;
87 }
88 }
89 else if (HttpFormDataDecoder::isValidType(__context->pszContentType)) {
90 // multipart-formdata
91 HttpInputStream input(this);
92#if 0
93 FileOutputStream output(__formFileMap.__tempDir + L"post.data", true);
94 Files::copy(input, output);
95#endif
96 HttpFormDataDecoder decoder;
97
98 decoder.decode(
99 input,
100 __context->pszContentType,
101 contentLength(),
102 __formMap,
103 __formFileMap
104 );
105#ifdef __DCL_DEBUG
106 if (!decoder.warnings().isEmpty()) {
107 __DCL_TRACE0(L"form-data decoding warnings\n");
108 __DCL_TRACE1(L"%ls\n", decoder.warnings().data());
109 }
110#endif
111 }
112 else {
113 __DCL_TRACE1(L"Unknown Content-Type[%ls]\n", contentType().data());
114 // unknown content-type
115 }
116 }
117
118 }
119}
120
125
127
128HttpServletEx::HttpServletEx()
129{
130 m_nMaxContentLength = 0; // unlimited
131
132#ifdef __DCL_DEBUG
133 m_bEnableDebugOut = true;
134#endif
135}
136
143
144#define __WSTR(s) UTF8Decoder::decode(s, ByteString::length(s))
145
146void HttpServletEx::onHttpService(
147 const DCL_HTTP_SERVLET_CONTEXT* pContext
149{
150 String tempPath;
151 if (__tempPath != NULL) {
152 tempPath = __tempPath;
153 }
154
155 if (tempPath.isEmpty()) {
156 String str = Files::dirname(__WSTR(pContext->pszScriptFilename));
157 String str2 = str + L"temp/";
158
159 if (Files::exists(str2))
160 tempPath = str2;
161 else
162 tempPath = str;
163 }
164
165#ifdef __DCL_DEBUG
166 StringWriter debugOut;
167 Writer* pOldOut = NULL;
168
169 // onService 내부에서 실수로 m_bEnableDebugOut 변경되는 것을 방지한다.
170 bool bEnableDebugOut = m_bEnableDebugOut;
171 if (bEnableDebugOut) {
172 pOldOut = DCLDebugSetThreadReport(
174 &debugOut
175 );
176 }
177
178 HttpServletContextEx ctx(__SAPI, pContext, tempPath);
179 try {
180 __DCL_TRACE1(L"initRequest __tempDir[% ls]\n", tempPath.data());
181 ctx.initRequest(m_nMaxContentLength);
182 __DCL_TRACE1(L"onService __tempDir [%ls]\n", tempPath.data());
183 onService(ctx);
184 // setStatusCode가 호출되고 write가 단 한번도 호출되지 않은경우
185 // 실제 HTTP HEADER가 전송되지 않는다.
186 // 헤더가 flush되지 않았으면 이를 전송한다.
187 // onService 내부에서 ctx.flushHeader나 ctx.write를 명시적으로
188 // 호출하지 않은 상태에서 예외가 발생하면 다음은 실행되지 않을 것이다.
189 ctx.flushHeader();
190
191 }
192 catch(Exception* e) {
193 if (pOldOut != NULL && debugOut.size() > 0) {
194 // debugOut에 보관된 TRACE 데이터를 기본 디버그 스트림으로
195 // 내보낸(flush) 후 예외를 다시 throw
196 try {
197 debugOut.flushTo(*pOldOut);
198 }
199 catch(Exception* e) {
200 e->destroy();
201 }
202 }
203
204 if (bEnableDebugOut) {
205 DCLDebugSetThreadReport(
207 pOldOut
208 );
209 }
210 throw e;
211 }
212
213 // 예외가 발생하지 않은 정상적인 상황
214 if (bEnableDebugOut) {
215 DCLDebugSetThreadReport(
217 pOldOut
218 );
219
220 if (pOldOut && debugOut.size() > 0) {
221 // 서블릿의 onInitRequest, onService에서 생성한 TRACE의 출력을 파일로..
222 pOldOut->write(debugOut.data(), debugOut.size());
223 }
224
225 if (/*ctx.m_pOutHtml
226 && */!ctx.__contentType.compareNoCase(L"text", 4)
227 && debugOut.size() > 0
228 )
229 {
230 Writer& writer = ctx.writer();
231 writer << L""
232 "\n<hr>\n<div style=\"color: black; background-color: white;\">\n"
233 "<h3>DCL Runtime Debugging Information</h3>\n"
234 "<pre style=\"font-size:10pt;\">\n";
235 debugOut.flushTo(writer);
236 writer << L"</pre>\n</div>\n";
237 }
238 }
239#else // __DCL_DEBUG
240
241 HttpServletContextEx ctx(__SAPI, pContext, tempPath);
242
243 ctx.initRequest(m_nMaxContentLength);
244 onService(ctx);
245 // setStatusCode가 호출되고 write가 단 한번도 호출되지 않은경우
246 // 실제 HTTP HEADER가 전송되지 않는다.
247 // 헤더가 flush되지 않았으면 이를 전송한다.
248 // onService 내부에서 ctx.flushHeader나 ctx.write를 명시적으로
249 // 호출하지 않은 상태에서 예외가 발생하면 다음은 실행되지 않을 것이다.
250 ctx.flushHeader();
251#endif
252
253 if (ctx.writer().size() > 0) {
254 if (ctx.__contentType.compareNoCase(L"text/html", 9) == 0)
255 ctx.writer() << L"</body>\n</html>\n";
256
257 UTF8Encoder encoder(false);
258 BytesOutputStream output;
259 OutputStreamWriter writer(output, encoder);
260
261 String content = ctx.writer().toString();
262 writer.write(content.data(), content.length());
263
264 ctx.addHeader(HttpHeader(L"Content-Length", String::valueOf(output.size())));
265 HttpOutputStream out(&ctx);
266 output.flushTo(out);
267 }
268}
269
270__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
wchar_t char_t
Definition Config.h:275
#define __DCL_THROWS1(e)
Definition Config.h:167
@ HTTP_METHOD_POST
struct _DCL_HTTP_SERVLET_CONTEXT DCL_HTTP_SERVLET_CONTEXT
struct _DCL_HTTP_SERVER_API DCL_HTTP_SERVER_API
#define __WSTR(s)
#define __DCL_TRACE0(psz)
Definition Object.h:375
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:376
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
ByteBuffer * buf
virtual void destroy()
Definition Exception.cpp:74
static String dirname(const String &_path)
Definition Files.cpp:269
static bool exists(const String &_path)
Definition Files.cpp:109
static size_t copy(InputStream &_input, OutputStream &_output) __DCL_THROWS1(IOException *)
Definition Files.cpp:520
void decode(InputStream &_input, const char *_contentType, size_t _contentLength, ListedStringToStringArrayMap &_mapForm, HttpFormData &_mapFormFile) __DCL_THROWS1(HttpFormDataDecoderException *)
const String warnings() const
static void decode(const ByteString &_queryString, ListedStringToStringArrayMap &_results)
static bool isValidType(const char *_contentType)
StringWriter __responseBuf
void initRequest(size_t nMaxContentLength) __DCL_THROWS1(FormDataException *)
virtual ~HttpServletContextEx()
HttpServletContextEx(const DCL_HTTP_SERVER_API *_SAPI, const DCL_HTTP_SERVLET_CONTEXT *_context, const String &_tempPath)
StringWriter & writer()
const DCL_HTTP_SERVLET_CONTEXT * __context
Definition HttpServlet.h:74
virtual void onInitialize() __DCL_THROWS1(Exception *)
size_t m_nMaxContentLength
virtual void onInitialize() __DCL_THROWS1(Exception *)
virtual String toString() const
Definition Object.cpp:187
virtual Writer & write(const wchar_t *_buf, size_t _n) __DCL_THROWS1(IOException *)
static unsigned long getCurrentThreadId()
Definition Thread.cpp:173