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