1 /*******************************************************************************
2 
3     HTTP exception classes
4 
5     - HttpServerException is the base class.
6     - HttpException is thrown when a request cannot be fulfilled to abort
7       request processing and immediately send the response. It contains the HTTP
8       response status code to send.
9     - HttpParseException is thrown on HTTP request or response message parse
10       error.
11     - HeaderParameterException is thrown when a required HTTP message header
12       parameter is missing or contains an invalid value.
13 
14     Copyright:
15         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
16         All rights reserved.
17 
18     License:
19         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
20         Alternatively, this file may be distributed under the terms of the Tango
21         3-Clause BSD License (see LICENSE_BSD.txt for details).
22 
23 *******************************************************************************/
24 
25 module ocean.net.http.HttpException;
26 
27 
28 import ocean.meta.types.Qualifiers;
29 
30 import ocean.core.Array: copy, concat;
31 import ocean.core.Enforce;
32 import ocean.core.Exception;
33 import ocean.net.http.consts.StatusCodes;
34 
35 import ocean.net.http.HttpConst: HttpResponseCode;
36 
37 
38 /******************************************************************************/
39 
40 class HttpServerException : Exception
41 {
42     mixin ReusableExceptionImplementation;
43 }
44 
45 
46 /******************************************************************************/
47 
48 class HttpException : HttpServerException
49 {
50     public HttpResponseCode status;
51 
52     public override typeof (this) set ( cstring msg, istring file = __FILE__,
53                                         long line = __LINE__ )
54     {
55         super.set(msg, file, line);
56         return this;
57     }
58 
59     public typeof (this) set (HttpResponseCode code, istring file = __FILE__,
60                               typeof(__LINE__) line = __LINE__)
61     {
62         this.status = code;
63         return this.set(this.status_phrase, file, line);
64     }
65 
66     istring status_phrase ( )
67     {
68         return StatusPhrases[this.status];
69     }
70 
71     /***************************************************************************
72 
73         Custom enforce for using an HTTP status code together with a set of
74         messages that should be appended.
75 
76         Params:
77             file = The filename
78             line = The line number
79             T = Types of messages to append
80             ok = The condition to enforce
81             code = The status code
82             messages = The messages
83 
84     ***************************************************************************/
85 
86     public void enforce ( istring file = __FILE__, long line = __LINE__, T ... )
87                         ( bool ok, HttpResponseCode code, T messages )
88     {
89         if ( !ok )
90         {
91             this.set(code, file, line);
92 
93             foreach ( msg; messages )
94             {
95                 this.append(" ");
96                 this.append(msg);
97             }
98 
99             throw this;
100         }
101     }
102 
103     version (unittest)
104     {
105         import ocean.core.Test;
106     }
107 
108     unittest
109     {
110         auto e = new HttpException();
111 
112         e.enforce(true, HttpResponseCode.OK);
113 
114         try
115         {
116             e.enforce(false, HttpResponseCode.OK, "Invalid resource");
117         }
118         catch (Exception)
119         {
120             test!("==")(e.status, HttpResponseCode.OK);
121             test!("==")(e.message(), "OK Invalid resource");
122         }
123 
124         try
125         {
126             auto path = "/path/with/errors";
127             e.enforce(false, HttpResponseCode.NotFound, "Unable to locate URI path:", path);
128         }
129         catch (Exception)
130         {
131             test!("==")(e.status, HttpResponseCode.NotFound);
132             test!("==")(e.message(), "Not Found Unable to locate URI path: /path/with/errors");
133         }
134     }
135 }
136 
137 
138 /******************************************************************************/
139 
140 class HttpParseException : HttpException {}
141 
142 
143 /******************************************************************************/
144 
145 class HeaderParameterException : HttpServerException {}