00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 module mango.http.server.HttpResponse;
00040
00041 private import mango.io.Buffer,
00042 mango.io.Writer;
00043
00044 private import mango.io.model.IWriter;
00045
00046 private import mango.http.HttpWriter;
00047
00048 private import mango.http.server.HttpParams,
00049 mango.http.server.HttpCookies,
00050 mango.http.server.HttpHeaders,
00051 mango.http.server.HttpMessage;
00052
00053 private import mango.http.server.model.IProviderBridge;
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 private static const int ParamsBufferSize = 1 * 1024;
00064 private static const int HeaderBufferSize = 4 * 1024;
00065
00066
00067
00068
00069
00070
00071
00072
00073 struct HttpStatus
00074 {
00075 int code;
00076 char[] name;
00077 }
00078
00079
00080
00081
00082
00083
00084
00085 enum HttpResponseCode
00086 {
00087 Continue = 100,
00088 SwitchingProtocols = 101,
00089 OK = 200,
00090 Created = 201,
00091 Accepted = 202,
00092 NonAuthoritativeInformation = 203,
00093 NoContent = 204,
00094 ResetContent = 205,
00095 PartialContent = 206,
00096 MultipleChoices = 300,
00097 MovedPermanently = 301,
00098 MovedTemporarily = 302,
00099 SeeOther = 303,
00100 NotModified = 304,
00101 UseProxy = 305,
00102 BadRequest = 400,
00103 Unauthorized = 401,
00104 PaymentRequired = 402,
00105 Forbidden = 403,
00106 NotFound = 404,
00107 MethodNotAllowed = 405,
00108 NotAcceptable = 406,
00109 ProxyAuthenticationRequired = 407,
00110 RequestTimeout = 408,
00111 Conflict = 409,
00112 Gone = 410,
00113 LengthRequired = 411,
00114 PreconditionFailed = 412,
00115 RequestEntityTooLarge = 413,
00116 RequestURITooLarge = 414,
00117 UnsupportedMediaType = 415,
00118 RequestedRangeNotSatisfiable = 416,
00119 ExpectationFailed = 417,
00120 InternalServerError = 500,
00121 NotImplemented = 501,
00122 BadGateway = 502,
00123 ServiceUnavailable = 503,
00124 GatewayTimeout = 504,
00125 VersionNotSupported = 505,
00126 };
00127
00128
00129
00130
00131
00132
00133
00134 struct HttpResponses
00135 {
00136 static final HttpStatus Continue = {HttpResponseCode.Continue, "Continue"};
00137 static final HttpStatus SwitchingProtocols = {HttpResponseCode.SwitchingProtocols, "SwitchingProtocols"};
00138 static final HttpStatus OK = {HttpResponseCode.OK, "OK"};
00139 static final HttpStatus Created = {HttpResponseCode.Created, "Created"};
00140 static final HttpStatus Accepted = {HttpResponseCode.Accepted, "Accepted"};
00141 static final HttpStatus NonAuthoritativeInformation = {HttpResponseCode.NonAuthoritativeInformation, "NonAuthoritativeInformation"};
00142 static final HttpStatus NoContent = {HttpResponseCode.NoContent, "NoContent"};
00143 static final HttpStatus ResetContent = {HttpResponseCode.ResetContent, "ResetContent"};
00144 static final HttpStatus PartialContent = {HttpResponseCode.PartialContent, "PartialContent"};
00145 static final HttpStatus MultipleChoices = {HttpResponseCode.MultipleChoices, "MultipleChoices"};
00146 static final HttpStatus MovedPermanently = {HttpResponseCode.MovedPermanently, "MovedPermanently"};
00147 static final HttpStatus MovedTemporarily = {HttpResponseCode.MovedTemporarily, "MovedTemporarily"};
00148 static final HttpStatus SeeOther = {HttpResponseCode.SeeOther, "SeeOther"};
00149 static final HttpStatus NotModified = {HttpResponseCode.NotModified, "NotModified"};
00150 static final HttpStatus UseProxy = {HttpResponseCode.UseProxy, "UseProxy"};
00151 static final HttpStatus BadRequest = {HttpResponseCode.BadRequest, "BadRequest"};
00152 static final HttpStatus Unauthorized = {HttpResponseCode.Unauthorized, "Unauthorized"};
00153 static final HttpStatus PaymentRequired = {HttpResponseCode.PaymentRequired, "PaymentRequired"};
00154 static final HttpStatus Forbidden = {HttpResponseCode.Forbidden, "Forbidden"};
00155 static final HttpStatus NotFound = {HttpResponseCode.NotFound, "NotFound"};
00156 static final HttpStatus MethodNotAllowed = {HttpResponseCode.MethodNotAllowed, "MethodNotAllowed"};
00157 static final HttpStatus NotAcceptable = {HttpResponseCode.NotAcceptable, "NotAcceptable"};
00158 static final HttpStatus ProxyAuthenticationRequired = {HttpResponseCode.ProxyAuthenticationRequired, "ProxyAuthenticationRequired"};
00159 static final HttpStatus RequestTimeout = {HttpResponseCode.RequestTimeout, "RequestTimeout"};
00160 static final HttpStatus Conflict = {HttpResponseCode.Conflict, "Conflict"};
00161 static final HttpStatus Gone = {HttpResponseCode.Gone, "Gone"};
00162 static final HttpStatus LengthRequired = {HttpResponseCode.LengthRequired, "LengthRequired"};
00163 static final HttpStatus PreconditionFailed = {HttpResponseCode.PreconditionFailed, "PreconditionFailed"};
00164 static final HttpStatus RequestEntityTooLarge = {HttpResponseCode.RequestEntityTooLarge, "RequestEntityTooLarge"};
00165 static final HttpStatus RequestURITooLarge = {HttpResponseCode.RequestURITooLarge, "RequestURITooLarge"};
00166 static final HttpStatus UnsupportedMediaType = {HttpResponseCode.UnsupportedMediaType, "UnsupportedMediaType"};
00167 static final HttpStatus RequestedRangeNotSatisfiable = {HttpResponseCode.RequestedRangeNotSatisfiable, "RequestedRangeNotSatisfiable"};
00168 static final HttpStatus ExpectationFailed = {HttpResponseCode.ExpectationFailed, "ExpectationFailed"};
00169 static final HttpStatus InternalServerError = {HttpResponseCode.InternalServerError, "InternalServerError"};
00170 static final HttpStatus NotImplemented = {HttpResponseCode.NotImplemented, "NotImplemented"};
00171 static final HttpStatus BadGateway = {HttpResponseCode.BadGateway, "BadGateway"};
00172 static final HttpStatus ServiceUnavailable = {HttpResponseCode.ServiceUnavailable, "ServiceUnavailable"};
00173 static final HttpStatus GatewayTimeout = {HttpResponseCode.GatewayTimeout, "GatewayTimeout"};
00174 static final HttpStatus VersionNotSupported = {HttpResponseCode.VersionNotSupported, "VersionNotSupported"};
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 class HttpResponse : HttpMessage
00186 {
00187 private HttpMutableParams params;
00188 private HttpMutableCookies cookies;
00189 private HttpStatus status;
00190 private HttpWriter writer;
00191 private bool commited;
00192
00193 static private InvalidStateException InvalidState;
00194
00195
00196
00197
00198
00199
00200
00201 static this()
00202 {
00203 InvalidState = new InvalidStateException("Invalid response state");
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 this (IProviderBridge bridge)
00216 {
00217
00218 super (bridge, new Buffer(HeaderBufferSize));
00219
00220
00221 writer = new HttpWriter (super.getBuffer());
00222
00223
00224
00225 params = new HttpMutableParams (new Buffer(ParamsBufferSize));
00226
00227
00228
00229
00230 cookies = new HttpMutableCookies (super.getHeader());
00231 }
00232
00233
00234
00235
00236
00237
00238
00239 void reset()
00240 {
00241
00242 commited = false;
00243 setStatus (HttpResponses.OK);
00244
00245
00246 super.reset();
00247
00248
00249 params.reset();
00250 }
00251
00252
00253
00254
00255
00256
00257
00258 void sendError (inout HttpStatus status)
00259 {
00260 sendError (status, "");
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270 void sendError (inout HttpStatus status, char[] msg)
00271 {
00272 sendError (status, status.name, msg);
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282 void sendError (inout HttpStatus status, Exception ex)
00283 {
00284 sendError (status, status.name, ex.toString());
00285 }
00286
00287
00288
00289
00290
00291
00292
00293 void setStatus (inout HttpStatus status)
00294 {
00295 this.status = status;
00296 }
00297
00298
00299
00300
00301
00302
00303
00304 HttpStatus getStatus ()
00305 {
00306 return status;
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 HttpWriter getWriter()
00318 {
00319
00320
00321 commit (writer);
00322 return writer;
00323 }
00324
00325
00326
00327
00328
00329
00330
00331 HttpMutableParams getOutputParams()
00332 {
00333 return params;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342 HttpMutableCookies getOutputCookies()
00343 {
00344 return cookies;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353 HttpMutableHeaders getOutputHeaders()
00354 {
00355
00356 if (commited)
00357 throw InvalidState;
00358 return super.getHeader();
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 IBuffer getOutputBuffer()
00370 {
00371
00372
00373 commit (writer);
00374 return super.getBuffer();
00375 }
00376
00377
00378
00379
00380
00381
00382
00383 void sendRedirect (char[] location)
00384 {
00385 setStatus (HttpResponses.MovedTemporarily);
00386 getHeader().add (HttpHeader.Location, location);
00387 flush (writer);
00388 }
00389
00390
00391
00392
00393
00394
00395
00396 void write (IWriter writer)
00397 {
00398 commit (writer);
00399 }
00400
00401
00402
00403
00404
00405
00406
00407 void flush (IWriter writer)
00408 {
00409 commit (writer);
00410
00411 version (ShowHeaders)
00412 {
00413 Stdout.put ("###############").cr();
00414 Stdout.put (super.getBuffer.toString).cr();
00415 Stdout.put ("###############").cr();
00416 }
00417 writer.flush();
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427 private void commit (IWriter writer)
00428 {
00429 if (! commited)
00430 {
00431
00432 commited = true;
00433
00434 char[] header;
00435 HttpMutableHeaders headers = getHeader();
00436
00437
00438 writer.put (HttpHeader.Version.value)
00439 .put (' ')
00440 .put (status.code)
00441 .put (' ')
00442 .put (status.name)
00443 .cr ();
00444
00445
00446 if (! headers.get (HttpHeader.Connection))
00447 headers.add (HttpHeader.Connection, "close");
00448
00449
00450 super.write (writer);
00451 writer.cr ();
00452
00453
00454 writer.flush();
00455
00456 version (ShowHeaders)
00457 {
00458 Stdout.put (">>>> output headers").cr();
00459 Stdout.put (HttpHeader.Version.value)
00460 .put (' ')
00461 .put (status.code)
00462 .put (' ')
00463 .put (status.name)
00464 .cr ();
00465 super.write (Stdout);
00466 }
00467 }
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 private void sendError (inout HttpStatus status, char[] reason, char[] message)
00479 {
00480 setStatus (status);
00481
00482 if (status.code != HttpResponses.NoContent.code &&
00483 status.code != HttpResponses.NotModified.code &&
00484 status.code != HttpResponses.PartialContent.code &&
00485 status.code >= HttpResponses.OK.code)
00486 {
00487
00488 setContentType (HttpHeader.TextHtml.value);
00489
00490
00491 commit (writer);
00492
00493
00494 writer.put ("<HTML>\n<HEAD>\n<TITLE>Error ")
00495 .put (status.code)
00496 .put (' ')
00497 .put (reason)
00498 .put ("</TITLE>\n<BODY>\n<H2>HTTP Error: ")
00499 .put (status.code)
00500 .put (' ')
00501 .put (reason)
00502 .put ("</H2>\n")
00503 .put (message ? message : "")
00504 .put ("\n</BODY>\n</HTML>\n");
00505
00506 flush (writer);
00507 }
00508 }
00509 }
00510
00511
00512