DCL 4.0
Loading...
Searching...
No Matches
HttpServlet.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#ifdef __DCL_DEBUG
17#include <dcl/Thread.h>
18#endif
19
20#include <dcl/Files.h>
21#include <dcl/Writer.h>
22#include <dcl/Exception.h>
23
24#include <dcl/HttpServlet.h>
25#include <dcl/Charset.h>
26#include <dcl/XFileWriter.h>
27#include <dcl/Writer.h>
28
29#if __DCL_DEBUG
30#undef __THIS_FILE__
31static const char_t* __THIS_FILE__ = __T("dcl/HttpServlet.cpp");
32#endif
33
34__DCL_BEGIN_NAMESPACE
35
37{
39public :
41 DCLHttpWriteStream pfnErrorReport,
42 void* hErrorReport,
43 Writer* pAltOutput
44 );
45
46 virtual Writer& write(const wchar_t* _buf, size_t _n)
48
49private:
50 DCLHttpWriteStream m_pfnReportError;
51 void* m_hErrorWriter;
52 Writer* m_pAltOutput;
53};
54
56
57ReportErrorWriter::ReportErrorWriter(
58 DCLHttpWriteStream pfnErrorReport,
59 void* hErrorReport,
60 Writer* pAltOutput
61 )
62{
63 //Writer::__name = L"HttpReportErrorBridge";
64
65 m_pfnReportError = pfnErrorReport;
66 m_hErrorWriter = hErrorReport;
67 m_pAltOutput = pAltOutput;
68}
69
70Writer& ReportErrorWriter::write(const wchar_t* _buf, size_t _n)
72{
73 // 결코 예외를 발생 시키지 않는다.
74 if (m_pAltOutput)
75 {
76 try
77 {
78 m_pAltOutput->write(_buf, _n);
79 }
80 catch(Exception* e)
81 {
82 e->destroy();
83 }
84 }
85 m_pfnReportError(m_hErrorWriter, (const char*)_buf, _n);
86 return *this;
87}
88
90
91HttpServletContext::HttpServletContext(
92 const DCL_HTTP_SERVER_API* _SAPI,
93 const DCL_HTTP_SERVLET_CONTEXT* _context
94 )
95{
96 __DCL_ASSERT(_SAPI != NULL);
97 __DCL_ASSERT(_context != NULL);
98 __DCL_ASSERT(_context->pszRemoteAddr != NULL);
99
101 __headerFlushed = false;
102
103 __SAPI = _SAPI;
104 __context = _context;
105}
106
107HttpServletContext::~HttpServletContext()
108{
109}
110
111ByteString HttpServletContext::getHttpHeader(
112 const char* _name // = NULL
113 ) const
114{
115 size_t len = 256;
116 if (!_name) {
117 len = 2048;
118 }
119
120 ByteBuffer* buf = ByteBuffer::create(len);
121 if (!__SAPI->pfnGetRequestHeader(
122 __context->hConn,
123 _name,
124 buf->data(),
125 &len)) {
126 if (len > 0) {
127 // insufficient buffer
128 ByteBuffer::extend(buf, len);
129 __DCL_VERIFY(__SAPI->pfnGetRequestHeader(
130 __context->hConn,
131 _name,
132 buf->data(),
133 &len) != FALSE);
134 }
135 }
136
137 __DCL_ASSERT(len <= buf->__allocLength);
138 *(buf->data() + len) = '\0';
139 buf->__dataLength = len;
140
141 ByteString r = buf;
142 buf->release();
143 return r;
144}
145
146ByteString HttpServletContext::getCgiVariable(
147 const char* _name // = NULL
148 ) const
149{
150 size_t len = 256;
151 if (!_name) {
152 len = 2048;
153 }
154
155 ByteBuffer* buf = ByteBuffer::create(len);
156 if (!__SAPI->pfnGetCgiVariable(
157 __context->hConn,
158 _name,
159 buf->data(),
160 &len
161 )) {
162 if (len > 0) {
163 // insufficient buffer
164 ByteBuffer::extend(buf, len);
165 __DCL_VERIFY(__SAPI->pfnGetCgiVariable(
166 __context->hConn,
167 _name,
168 buf->data(),
169 &len) != FALSE);
170 }
171 }
172
173 __DCL_ASSERT(len <= buf->__allocLength);
174 *(buf->data() + len) = '\0';
175 buf->__dataLength = len;
176
177 ByteString r = buf;
178 buf->release();
179 return r;
180}
181
182String HttpServletContext::getHttpHeader(
183 const wchar_t* _name // = NULL
184 ) const
185{
186 if (_name) {
188 HttpServletContext::getHttpHeader(
189 AsciiEncoder::encode(_name, (size_t)-1)
190 )
191 );
192 }
193 else {
195 HttpServletContext::getHttpHeader((const char*)NULL)
196 );
197 }
198}
199
200String HttpServletContext::getCgiVariable(
201 const wchar_t* _name // = NULL
202 ) const
203{
204 if (_name) {
205 return UTF8Decoder::decode(
206 HttpServletContext::getCgiVariable(
207 UTF8Encoder::encode(_name, (size_t)-1)
208 )
209 );
210 }
211 else {
212 return UTF8Decoder::decode(
213 HttpServletContext::getCgiVariable((const char*)NULL)
214 );
215 }
216}
217
218size_t HttpServletContext::read(
219 void* pv,
220 size_t n
222{
224
225 if (!__SAPI->pfnReadClient(
226 __context->hConn,
227 pv,
228 &n
229 )) {
230 throw new IOException(
231 remoteAddr(),
232 L"HTTP Connection error"
233 );
234 }
235
236 return n;
237}
238
239void HttpServletContext::setStatusCode(unsigned int uHttpStatusCode)
240{
242 __statusCode = uHttpStatusCode;
243 if (uHttpStatusCode == HTTP_STATUS_NOT_FOUND)
244 setContentType(L"text/html");
245}
246
247
248void HttpServletContext::setContentType(const wchar_t* _contentType, const wchar_t* pszCharset /* = NULL */)
249{
251
252 __DCL_ASSERT(_contentType != NULL);
253 __contentType = _contentType;
254 if (pszCharset) {
256 if (pszCharset) {
257 __contentType = __contentType + L"charset=";
258 __contentType = __contentType + pszCharset;
259 }
260 }
261}
262
263void HttpServletContext::addHeader(const HttpHeader& httpHeader)
264{
266
267 if (!httpHeader.name().compareNoCase(L"Content-Type"))
268 __contentType = httpHeader.content();
269 else
270 __responseHeaders += httpHeader.toString() + L"\r\n";
271}
272
273void HttpServletContext::flushHeader()
274{
276
277 if (__headerFlushed)
278 return;
279
280 if (!__contentType.isEmpty()) {
281 __responseHeaders += L"Content-Type: ";
282 __responseHeaders += __contentType + L"\r\n";
283 }
284
285 __responseHeaders += L"\r\n";
286
287 ByteString s = UTF8Encoder::encode(__responseHeaders.toString());
288
289 __SAPI->pfnSendResponseHeader(
290 __context->hConn,
292 s.data(),
293 s.length()
294 );
295
296 __headerFlushed = true;
297}
298
299void HttpServletContext::write(
300 const void* pv,
301 size_t n
303{
305 __DCL_ASSERT(__context != NULL);
306
307 if (!__headerFlushed)
308 flushHeader();
309
310 size_t len = n;
311 if (!__SAPI->pfnWriteClient(
312 __context->hConn,
313 pv,
314 &len
315 )) {
316 throw new IOException(
317 remoteAddr(),
318 L"http connection error"
319 );
320 }
321
322 __DCL_TRACE2(L"pfnWriteClient [%zd] [%zd]\n", n, len);
323}
324
326
327HttpServlet::HttpServlet()
328{
331 __SAPI = NULL;
332}
333
334String HttpServlet::getIniFileName(
335 const wchar_t* _basename // = NULL
336 ) const
337{
338 String basename;
339
340 if (_basename) {
341 __DCL_ASSERT(*_basename != '\0');
342 basename = _basename;
343 }
344 else {
345 basename = Files::basename(__moduleName);
346 size_t index = basename.lastIndexOf('.');
347 if (index != (size_t) -1) {
348 __DCL_ASSERT(index > 0);
349 basename = basename.left(index);
350 }
351 basename = basename + L".ini";
352 }
353
354 if (__configPath) {
355 String path = __configPath;
356 if (!path.endsWith(L"/")) {
357 path = path + L'/';
358 }
359 path = path + basename;
360 if (Files::exists(path)) {
361 return path;
362 }
363
364 }
365
366 String dir = Files::dirname(__moduleName);
367 if (!dir.endsWith(L"/")) {
368 dir = dir + L'/';
369 }
370 return dir + basename;
371}
372
377
382
383// DCL_HTTP_SERVLET member function Helper
384#ifdef __DCL_DEBUG
385static XFileWriter* __pDebugFileOut = NULL;
386#endif
388 HttpServlet* _servlet,
389 const DCL_HTTP_SERVLET_CONFIG* _config,
390 void* hErrorReport
391 )
392{
393#ifdef __DCL_DEBUG
394 __DCL_ASSERT(_config != NULL
395 && _config->pszModuleName != NULL
396 && *(_config->pszModuleName) != L'\0'
397 );
398 __DCL_ASSERT(_config->pSAPI != NULL);
399#endif
400
401 _servlet->__moduleName = _config->pszModuleName;
402 _servlet->__configPath = _config->pszConfigPath;
403 _servlet->__tempPath = _config->pszTempPath;
404 _servlet->__SAPI = _config->pSAPI;
405
406#ifdef __DCL_DEBUG
407 String filename = _servlet->__moduleName;
408 filename = filename.left(filename.lastIndexOf(L'.')) + L".dump.txt";
409 try {
410 // Mutexted FileWriter
411 __pDebugFileOut =
412 new XFileWriter(filename, false, new UTF8Encoder());
413 }
414 catch(IOException* e) {
416 L"Warning! dump file create fail. [%ls]: [%ls]\n",
417 filename.data(),
418 e->toString().data()
419 );
420 e->destroy();
421 }
422#endif
423
424#ifdef __DCL_DEBUG
425 ReportErrorWriter output(
426 _servlet->__SAPI->pfnReportError,
427 hErrorReport,
428 __pDebugFileOut
429 );
430
431 Writer* pOldOutput =
432 DCLDebugSetThreadReport(
434 &output
435 );
436
437#else
438 ReportErrorWriter output(
439 _servlet->__SAPI->pfnReportError,
440 hErrorReport,
441 NULL
442 );
443#endif
444
445 bool result = TRUE;
446 try {
447 __DCL_TRACE1(L"begin __initialize [%ls]\n", _servlet->__moduleName);
448 _servlet->onInitialize();
449 __DCL_TRACE1(L"end __initialize [%ls]\n", _servlet->__moduleName);
450 }
451 catch (Exception* _e) {
452 output << _e->toStringAll() << endl;
453 _e->destroy();
454 result = FALSE;
455 }
456
457#ifdef __DCL_DEBUG
458 DCLDebugSetThreadReport(
460 pOldOutput
461 );
462
463 if (!result && __pDebugFileOut) {
464 delete __pDebugFileOut;
465 __pDebugFileOut = NULL;
466 }
467#endif
468
469 return result;
470}
471
473 HttpServlet* _servlet,
474 void* hErrorReport
475 )
476{
477#ifdef __DCL_DEBUG
478 ReportErrorWriter output(
479 _servlet->__SAPI->pfnReportError,
480 hErrorReport,
481 __pDebugFileOut
482 );
483
484 Writer* pOldOutput = pOldOutput =
485 DCLDebugSetThreadReport(
487 &output
488 );
489
490#else
491 ReportErrorWriter output(
492 _servlet->__SAPI->pfnReportError,
493 hErrorReport,
494 NULL
495 );
496#endif
497
498 bool result = TRUE;
499 try {
500 __DCL_TRACE1(L"begin __cleanup [%ls]\n", _servlet->__moduleName);
501 _servlet->onCleanup();
502 __DCL_TRACE1(L"end __cleanup [%ls]\n", _servlet->__moduleName);
503 }
504 catch (Exception* e) {
505 output << e->toStringAll() << endl;
506 e->destroy();
507 result = FALSE;
508 }
509
510#ifdef __DCL_DEBUG
511 pOldOutput = DCLDebugSetThreadReport(
513 pOldOutput
514 );
515
516 if (pOldOutput != &output) {
517 __DCL_TRACE0(L"Assertion Fail! 'pOldOutput == &writer'\n");
518 }
519
520 if (__pDebugFileOut) {
521 delete __pDebugFileOut;
522 __pDebugFileOut = NULL;
523 }
524#endif
525
526 return result;
527}
528
530 HttpServlet* _servlet,
531 const DCL_HTTP_SERVLET_CONTEXT* _context,
532 void* hErrorReport
533 )
534{
535#ifdef __DCL_DEBUG
536 ReportErrorWriter output(
537 _servlet->__SAPI->pfnReportError,
538 hErrorReport,
539 __pDebugFileOut
540 );
541
542 Writer* pOldOutput =
543 DCLDebugSetThreadReport(
545 &output
546 );
547
548 const void* pLastAllocPosition =
549 DCLDebugGetLastAllocPosition(
551 );
552#else
553 ReportErrorWriter output(
554 _servlet->__SAPI->pfnReportError,
555 hErrorReport,
556 NULL
557 );
558#endif
559
560 bool result = TRUE;
561 try {
562 __DCL_TRACE1(L"begin __httpService [%ls]\n", _servlet->__moduleName);
563 _servlet->onHttpService(_context);
564 __DCL_TRACE1(L"end __httpService [%ls]\n", _servlet->__moduleName);
565 }
566 catch (Exception* e) {
567 String s = e->toStringAll();
568 __DCL_TRACE2(L"catch __httpService [%ls][%ls]\n", _servlet->__moduleName,
569 s.data());
570 output << s << endl;
571 e->destroy();
572 result = FALSE;
573 }
574
575#ifdef __DCL_DEBUG
576 DCLDebugDumpThreadMemoryLeak(
578 pLastAllocPosition,
579 DCL_ALLOC_DUMP_ALL,
580 &output
581 );
582
583 DCLDebugSetThreadReport(
585 pOldOutput
586 );
587#endif
588
589 return result;
590}
591
592#define __WSTR(s) s ? UTF8Decoder::decode(s, ByteString::length(s)) : String()
593
594String HttpServletContext::remoteAddr() const
595{
598}
599
600unsigned int HttpServletContext::remotePort() const
601{
603 return __context->uRemotePort;
604}
605
606String HttpServletContext::method() const
607{
609 return __WSTR(__context->pszRequestMethod);
610}
611
612unsigned int HttpServletContext::methodNo() const
613{
615 return __context->uRequestMethod;
616}
617
618String HttpServletContext::path() const
619{
621 return __WSTR(__context->pszPath);
622}
623
624String HttpServletContext::queryString() const
625{
627 return __WSTR(__context->pszQueryString);
628}
629
630String HttpServletContext::contentType() const
631{
633 return __WSTR(__context->pszContentType);
634}
635
636size_t HttpServletContext::contentLength() const
637{
639 return __context->uContentLength;
640}
641
642String HttpServletContext::scriptFilename() const
643{
645 return __WSTR(__context->pszScriptFilename);
646}
647
648String HttpServletContext::scriptData() const
649{
651 return String(__context->pszScriptData,
652 __context->uScriptLength);
653}
654
655const String& HttpServletContext::resContentType() const
656{
657 return __contentType;
658}
659
660__DCL_END_NAMESPACE
661/*
662#if defined(_WINDOWS) && defined(_USRDLL)
663bool APIENTRY DllMain( HANDLE hModule,
664 DWORD ul_reason_for_call,
665 LPVOID lpReserved
666 )
667{
668 switch (ul_reason_for_call)
669 {
670 case DLL_PROCESS_ATTACH:
671 __DCL_TRACE0("DCLHExtd.dll DLL_PROCESS_ATTACH\n");
672 break;
673 case DLL_PROCESS_DETACH:
674 __DCL_TRACE0("DCLHExtd.dll DLL_PROCESS_DETACH\n");
675 break;
676 case DLL_THREAD_ATTACH:
677 __DCL_TRACE0("DCLHExtd.dll DLL_THREAD_ATTACH\n");
678 break;
679 case DLL_THREAD_DETACH:
680 __DCL_TRACE0("DCLHExtd.dll DLL_THREAD_DETACH\n");
681 break;
682 }
683 return TRUE;
684}
685#endif
686*/
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
#define INT32_MAX
Definition Config.h:318
wchar_t char_t
Definition Config.h:275
#define __DCL_THROWS1(e)
Definition Config.h:167
struct _DCL_HTTP_SERVLET_CONTEXT DCL_HTTP_SERVLET_CONTEXT
void(* DCLHttpWriteStream)(void *hWriter, const void *pvData, size_t uLength)
struct _DCL_HTTP_SERVER_API DCL_HTTP_SERVER_API
@ HTTP_STATUS_OK
@ HTTP_STATUS_NOT_FOUND
#define TRUE
#define FALSE
struct _DCL_HTTP_SERVLET_CONFIG DCL_HTTP_SERVLET_CONFIG
#define __WSTR(s)
#define __DCL_TRACE0(psz)
Definition Object.h:375
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:376
#define __DCL_VERIFY(expr)
Definition Object.h:373
#define DECLARE_CLASSINFO(class_name)
Definition Object.h:210
#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
#define __DCL_TRACE2(fmt, arg1, arg2)
Definition Object.h:377
#define endl
ByteString r
size_t len
ByteBuffer * buf
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
return result
static String decode(const char *_mbs, size_t _mbslen=(size_t) -1)
virtual void destroy()
Definition Exception.cpp:74
String toStringAll() const
Definition Exception.cpp:45
static String dirname(const String &_path)
Definition Files.cpp:269
static bool exists(const String &_path)
Definition Files.cpp:109
static String basename(const String &_path)
Definition Files.cpp:253
const String & content() const
Definition HttpHeader.h:97
String toString() const
const String & name() const
Definition HttpHeader.h:92
const DCL_HTTP_SERVLET_CONTEXT * __context
Definition HttpServlet.h:74
unsigned int __statusCode
Definition HttpServlet.h:77
const DCL_HTTP_SERVER_API * __SAPI
Definition HttpServlet.h:73
StringBuilder __responseHeaders
Definition HttpServlet.h:78
static bool __cleanup(HttpServlet *_servlet, void *hErrorReport)
virtual void onInitialize() __DCL_THROWS1(Exception *)
static bool __httpService(HttpServlet *_servlet, const DCL_HTTP_SERVLET_CONTEXT *_context, void *hErrorReport)
virtual void onHttpService(const DCL_HTTP_SERVLET_CONTEXT *pContext)=0__DCL_THROWS1(Exception *)
const DCL_HTTP_SERVER_API * __SAPI
const wchar_t * __moduleName
const wchar_t * __configPath
virtual void onCleanup() __DCL_THROWS1(Exception *)
const wchar_t * __tempPath
static bool __initialize(HttpServlet *_servlet, const DCL_HTTP_SERVLET_CONFIG *_config, void *hErrorReport)
virtual String toString() const
static unsigned long getCurrentThreadId()
Definition Thread.cpp:173
DCLHttpWriteStream pfnReportError
const DCL_HTTP_SERVER_API * pSAPI