1 /*****************************************************************
2 |
3 |      HTTP Server Test Program 1
4 |
5 |      (c) 2001-2006 Gilles Boccon-Gibod
6 |      Author: Gilles Boccon-Gibod (bok@bok.net)
7 |
8  ****************************************************************/
9 
10 /*----------------------------------------------------------------------
11 |       includes
12 +---------------------------------------------------------------------*/
13 #include "Neptune.h"
14 #include "NptDebug.h"
15 
16 #if defined(WIN32) && defined(_DEBUG)
17 #include <crtdbg.h>
18 #endif
19 
20 bool KillRequest = false;
21 
22 /*----------------------------------------------------------------------
23 |       KillHandler
24 +---------------------------------------------------------------------*/
25 class KillHandler : public NPT_HttpRequestHandler
26 {
27 public:
SetupResponse(NPT_HttpRequest &,const NPT_HttpRequestContext &,NPT_HttpResponse & response)28     NPT_Result SetupResponse(NPT_HttpRequest&              /*request*/,
29                              const NPT_HttpRequestContext& /*context*/,
30                              NPT_HttpResponse&             response) {
31         NPT_HttpEntity* entity = response.GetEntity();
32         entity->SetContentType("text/html");
33         entity->SetInputStream("<html><body>Bye Bye!</body></html>");
34         KillRequest = true;
35 
36         return NPT_SUCCESS;
37     }
38 };
39 
40 /*----------------------------------------------------------------------
41 |       TestHandler1
42 +---------------------------------------------------------------------*/
43 class TestHandler1 : public NPT_HttpRequestHandler
44 {
45 public:
TestHandler1(bool chunked=false)46     TestHandler1(bool chunked = false) : m_Chunked(chunked) {}
SetupResponse(NPT_HttpRequest & request,const NPT_HttpRequestContext & context,NPT_HttpResponse & response)47     NPT_Result SetupResponse(NPT_HttpRequest&              request,
48                              const NPT_HttpRequestContext& context,
49                              NPT_HttpResponse&             response) {
50         NPT_String msg = "<HTML>";
51         msg += "PATH=";
52         msg += request.GetUrl().GetPath();
53         msg += "<P><B>Local Address:</B> ";
54         msg += context.GetLocalAddress().ToString();
55         msg += "<P>";
56         msg += "<B>Remote Address:</B> ";
57         msg += context.GetRemoteAddress().ToString();
58         msg += "<P><UL>";
59         if (request.GetUrl().HasQuery()) {
60             NPT_UrlQuery query(request.GetUrl().GetQuery());
61             for (NPT_List<NPT_UrlQuery::Field>::Iterator it = query.GetFields().GetFirstItem();
62                  it;
63                  ++it) {
64                  NPT_UrlQuery::Field& field = *it;
65                  msg += "<LI>";
66                  msg += field.m_Name;
67                  msg += " = ";
68                  msg += field.m_Value;
69                  msg += " </LI>";
70 
71                  // check for a 'delay' field
72                  if (field.m_Name == "delay") {
73                     NPT_UInt32 delay = 0;
74                     field.m_Value.ToInteger(delay);
75                     NPT_Debug("DELAY: %d seconds\n", delay);
76                     NPT_System::Sleep(NPT_TimeInterval((float)delay));
77                  }
78             }
79         }
80         msg += "</UL></HTML>";
81 
82 
83         if (request.GetMethod() == NPT_HTTP_METHOD_POST) {
84             NPT_DataBuffer request_body;
85             request.GetEntity()->Load(request_body);
86             NPT_Debug("REQUEST: body = %d bytes\n", request_body.GetDataSize());
87             NPT_Debug("REQUEST: content type = %s\n", request.GetEntity()->GetContentType().GetChars());
88             if (request.GetEntity()->GetContentType().StartsWith("text") ||
89                 request.GetEntity()->GetContentType() == "application/x-www-form-urlencoded") {
90                 NPT_String body_string;
91                 body_string.Assign((char*)request_body.GetData(), request_body.GetDataSize());
92                 NPT_Debug("%s", body_string.GetChars());
93             }
94         }
95 
96         NPT_HttpEntity* entity = response.GetEntity();
97         entity->SetContentType("text/html");
98         entity->SetInputStream(msg);
99 
100         if (m_Chunked) {
101             entity->SetTransferEncoding(NPT_HTTP_TRANSFER_ENCODING_CHUNKED);
102             entity->SetContentLength(0);
103         }
104 
105         return NPT_SUCCESS;
106     }
107 
108     bool m_Chunked;
109 };
110 
111 /*----------------------------------------------------------------------
112 |       TestHandler2
113 +---------------------------------------------------------------------*/
114 class TestHandler2 : public NPT_HttpRequestHandler
115 {
116 public:
SetupResponse(NPT_HttpRequest &,const NPT_HttpRequestContext &,NPT_HttpResponse & response)117     NPT_Result SetupResponse(NPT_HttpRequest&              /*request*/,
118                              const NPT_HttpRequestContext& /*context*/,
119                              NPT_HttpResponse&             response) {
120         NPT_HttpEntity* entity = response.GetEntity();
121         entity->SetContentType("text/html");
122         return NPT_SUCCESS;
123     }
124 
SendResponseBody(const NPT_HttpRequestContext &,NPT_HttpResponse &,NPT_OutputStream & output)125     NPT_Result SendResponseBody(const NPT_HttpRequestContext& /*context*/,
126                                 NPT_HttpResponse&             /*response*/,
127                                 NPT_OutputStream&             output) {
128         output.WriteString("<html><body>\r\n");
129         for (unsigned int i=0; i<30; i++) {
130             output.WriteString("Line ");
131             output.WriteString(NPT_String::FromInteger(i).GetChars());
132             output.WriteString("\r\n");
133             output.Flush();
134             NPT_System::Sleep(NPT_TimeInterval(0.2f));
135         }
136         output.WriteString("</body></html>\r\n");
137         return NPT_SUCCESS;
138     }
139 };
140 
141 /*----------------------------------------------------------------------
142 |       ChunkedHandler
143 +---------------------------------------------------------------------*/
144 class ChunkedHandler : public NPT_HttpRequestHandler
145 {
146 public:
SetupResponse(NPT_HttpRequest &,const NPT_HttpRequestContext &,NPT_HttpResponse & response)147     NPT_Result SetupResponse(NPT_HttpRequest&              /*request*/,
148                              const NPT_HttpRequestContext& /*context*/,
149                              NPT_HttpResponse&             response) {
150         NPT_HttpEntity* entity = response.GetEntity();
151         entity->SetContentType("text/html");
152         entity->SetTransferEncoding("chunked");
153         response.SetProtocol(NPT_HTTP_PROTOCOL_1_1);
154         return NPT_SUCCESS;
155     }
156 
SendResponseBody(const NPT_HttpRequestContext &,NPT_HttpResponse &,NPT_OutputStream & output)157     NPT_Result SendResponseBody(const NPT_HttpRequestContext& /*context*/,
158                                 NPT_HttpResponse&             /*response*/,
159                                 NPT_OutputStream&             output) {
160         NPT_HttpChunkedOutputStream chunker(output);
161         chunker.WriteString("<html><body>\r\n");
162         for (unsigned int i=0; i<30; i++) {
163             NPT_String line = "Line ";
164             line += NPT_String::FromInteger(i).GetChars();
165             chunker.WriteString(line.GetChars());
166             chunker.Flush();
167             NPT_System::Sleep(NPT_TimeInterval(0.2f));
168         }
169         chunker.WriteString("</body></html>\r\n");
170         return NPT_SUCCESS;
171     }
172 };
173 
174 /*----------------------------------------------------------------------
175 |       TestHttp
176 +---------------------------------------------------------------------*/
177 static NPT_Result
TestHttp()178 TestHttp()
179 {
180     NPT_HttpServer            server(1234);
181     NPT_InputStreamReference  input;
182     NPT_OutputStreamReference output;
183     NPT_HttpRequestContext    context;
184 
185     NPT_HttpStaticRequestHandler* static_handler = new NPT_HttpStaticRequestHandler(
186         "<html><body>"
187         "<h1>Neptune HTTP Server Test 1</h1>"
188         "<a href='/files-autodir'>List files working directory (autodir)</a><br>"
189         "<a href='/files'>List files working directory (no autodir)</a><br>"
190         "<a href='/test1'>Test 1</a><br>"
191         "<a href='/test2'>Test 2</a><br>"
192         "<a href='/chunked1'>Chunked 1</a><br>"
193         "<a href='/chunked2'>Chunked 2</a><br>"
194         "<a href='/kill'>Kill Test Server</a><br>"
195         "</body></html>",
196         "text/html");
197     server.AddRequestHandler(static_handler, "/", false);
198 
199     KillHandler* kill_handler = new KillHandler();
200     server.AddRequestHandler(kill_handler, "/kill", false);
201 
202     TestHandler1* test_handler1 = new TestHandler1();
203     server.AddRequestHandler(test_handler1, "/test1", false);
204 
205     TestHandler2* test_handler2 = new TestHandler2();
206     server.AddRequestHandler(test_handler2, "/test2", false);
207 
208     ChunkedHandler* chunked_handler1 = new ChunkedHandler();
209     server.AddRequestHandler(chunked_handler1, "/chunked1", false);
210 
211     TestHandler1* chunked_handler2 = new TestHandler1(true);
212     server.AddRequestHandler(chunked_handler2, "/chunked2", false);
213 
214     NPT_String cwd;
215     NPT_File::GetWorkingDir(cwd);
216     NPT_HttpFileRequestHandler* file_handler_autodir = new NPT_HttpFileRequestHandler("/files-autodir", cwd.GetChars(), true);
217     server.AddRequestHandler(file_handler_autodir, "/files-autodir", true);
218     NPT_HttpFileRequestHandler* file_handler_noautodir = new NPT_HttpFileRequestHandler("/files", cwd.GetChars(), false);
219     server.AddRequestHandler(file_handler_noautodir, "/files", true);
220 
221     do {
222         NPT_Console::Output("Test HTTP server waiting for connection on port 1234...\n");
223         NPT_Result result = server.WaitForNewClient(input,
224                                                     output,
225                                                     &context);
226         NPT_Console::OutputF("WaitForNewClient returned %d (%s)\n", result, NPT_ResultText(result));
227         if (NPT_FAILED(result)) return result;
228 
229         result = server.RespondToClient(input, output, context);
230         NPT_Console::OutputF("RespondToClient returned %d (%s)\n", result, NPT_ResultText(result));
231 
232         input = NULL;
233         output = NULL;
234     } while (!KillRequest);
235 
236     NPT_Console::OutputF("Killing Server\n");
237 
238     delete static_handler;
239     delete test_handler1;
240     delete test_handler2;
241     delete file_handler_autodir;
242     delete file_handler_noautodir;
243 
244     return NPT_SUCCESS;
245 }
246 
247 /*----------------------------------------------------------------------
248 |       main
249 +---------------------------------------------------------------------*/
250 int
main(int,char **)251 main(int /*argc*/, char** /*argv*/)
252 {
253     // setup debugging
254 #if defined(WIN32) && defined(_DEBUG)
255     int flags = _crtDbgFlag       |
256         _CRTDBG_ALLOC_MEM_DF      |
257         _CRTDBG_DELAY_FREE_MEM_DF |
258         _CRTDBG_CHECK_ALWAYS_DF;
259 
260     _CrtSetDbgFlag(flags);
261     //AllocConsole();
262     //freopen("CONOUT$", "w", stdout);
263 #endif
264 
265     TestHttp();
266 
267 #if defined(WIN32) && defined(_DEBUG)
268     _CrtDumpMemoryLeaks();
269 #endif
270 
271     return 0;
272 }
273