1 /* 2 DSFML - The Simple and Fast Multimedia Library for D 3 4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 6 This software is provided 'as-is', without any express or implied warranty. 7 In no event will the authors be held liable for any damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial applications, 10 and to alter it and redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 14 15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 16 17 3. This notice may not be removed or altered from any source distribution 18 */ 19 20 ///A module containing the Http class. 21 module dsfml.network.http; 22 23 import core.time; 24 25 /** 26 *A HTTP client. 27 * 28 *sf::Http is a very simple HTTP client that allows you to communicate with a web server. 29 * 30 *You can retrieve web pages, send data to an interactive resource, download a remote file, etc. 31 */ 32 class Http 33 { 34 package sfHttp* sfPtr; 35 36 ///Default constructor 37 this() 38 { 39 sfPtr = sfHttp_create(); 40 } 41 42 ///Construct the HTTP client with the target host. 43 /// 44 ///This is equivalent to calling setHost(host, port). The port has a default value of 0, which means that the HTTP client will use the right port according to the protocol used (80 for HTTP, 443 for HTTPS). You should leave it like this unless you really need a port other than the standard one, or use an unknown protocol. 45 /// 46 ///Params: 47 /// host = Web server to connect to. 48 /// port = Port to use for connection. 49 this(string host, ushort port = 0) 50 { 51 import dsfml.system..string; 52 sfPtr = sfHttp_create(); 53 sfHttp_setHost(sfPtr, toStringz(host),port); 54 } 55 56 ///Destructor 57 ~this() 58 { 59 import dsfml.system.config; 60 mixin(destructorOutput); 61 sfHttp_destroy(sfPtr); 62 } 63 64 ///Set the target host. 65 /// 66 ///This function just stores the host address and port, it doesn't actually connect to it until you send a request. The port has a default value of 0, which means that the HTTP client will use the right port according to the protocol used (80 for HTTP, 443 for HTTPS). You should leave it like this unless you really need a port other than the standard one, or use an unknown protocol. 67 /// 68 ///Params: 69 /// host = Web server to connect to. 70 /// port = Port to use for connection. 71 void setHost(string host, ushort port = 0) 72 { 73 import dsfml.system..string; 74 sfHttp_setHost(sfPtr, toStringz(host),port); 75 } 76 77 ///Send a HTTP request and return the server's response. 78 /// 79 ///You must have a valid host before sending a request (see setHost). Any missing mandatory header field in the request will be added with an appropriate value. Warning: this function waits for the server's response and may not return instantly; use a thread if you don't want to block your application, or use a timeout to limit the time to wait. A value of Time::Zero means that the client will use the system defaut timeout (which is usually pretty long). 80 /// 81 ///Params: 82 /// request = Request to send. 83 /// timeout = Maximum time to wait. 84 Response sendRequest(Request request, Duration timeout = Duration.zero()) 85 { 86 return new Response(sfHttp_sendRequest(sfPtr,request.sfPtrRequest,timeout.total!"usecs")); 87 } 88 89 ///Define a HTTP request. 90 static class Request 91 { 92 ///Enumerate the available HTTP methods for a request. 93 enum Method 94 { 95 ///Request in get mode, standard method to retrieve a page. 96 Get, 97 ///Request in post mode, usually to send data to a page. 98 Post, 99 ///Request a page's header only. 100 Head 101 } 102 103 package sfHttpRequest* sfPtrRequest; 104 105 ///This constructor creates a GET request, with the root URI ("/") and an empty body. 106 /// 107 ///Params: 108 /// uri = Target URI. 109 /// method = Method to use for the request. 110 /// body = Content of the request's body. 111 this(string uri = "/", Method method = Method.Get, string requestBody = "") 112 { 113 import dsfml.system..string; 114 sfPtrRequest = sfHttpRequest_create(); 115 sfHttpRequest_setUri(sfPtrRequest, toStringz(uri)); 116 sfHttpRequest_setMethod(sfPtrRequest, method); 117 sfHttpRequest_setBody(sfPtrRequest,toStringz(requestBody)); 118 } 119 120 ///Destructor 121 ~this() 122 { 123 import std.stdio; 124 writeln("Destroying HTTP Request"); 125 sfHttpRequest_destroy(sfPtrRequest); 126 } 127 128 ///Set the body of the request. 129 /// 130 ///The body of a request is optional and only makes sense for POST requests. It is ignored for all other methods. The body is empty by default. 131 /// 132 ///Params: 133 /// body = Content of the body. 134 void setBody(string requestBody) 135 { 136 import dsfml.system..string; 137 sfHttpRequest_setBody(sfPtrRequest,toStringz(requestBody)); 138 } 139 140 ///Set the value of a field. 141 /// 142 ///The field is created if it doesn't exist. The name of the field is case insensitive. By default, a request doesn't contain any field (but the mandatory fields are added later by the HTTP client when sending the request). 143 /// 144 ///Params: 145 /// field = Name of the field to set. 146 /// value = Value of the field. 147 void setField(string feild, string value) 148 { 149 import dsfml.system..string; 150 sfHttpRequest_setField(sfPtrRequest,toStringz(feild),toStringz(value)); 151 } 152 153 ///Set the HTTP version for the request. 154 /// 155 ///The HTTP version is 1.0 by default. 156 /// 157 ///Parameters 158 /// major = Major HTTP version number. 159 /// minor = Minor HTTP version number. 160 void setHttpVersion(uint major, uint minor) 161 { 162 sfHttpRequest_setHttpVersion(sfPtrRequest,major, minor); 163 } 164 165 ///Set the request method. 166 /// 167 ///See the Method enumeration for a complete list of all the availale methods. The method is Http::Request::Get by default. 168 /// 169 ///Params 170 /// method = Method to use for the request. 171 void setMethod(Method method) 172 { 173 sfHttpRequest_setMethod(sfPtrRequest,method); 174 } 175 176 ///Set the requested URI. 177 /// 178 ///The URI is the resource (usually a web page or a file) that you want to get or post. The URI is "/" (the root page) by default. 179 /// 180 ///Params 181 /// uri = URI to request, relative to the host. 182 void setUri(string uri) 183 { 184 import dsfml.system..string; 185 sfHttpRequest_setUri(sfPtrRequest,toStringz(uri)); 186 } 187 } 188 189 ///Define a HTTP response. 190 class Response 191 { 192 ///Enumerate all the valid status codes for a response. 193 enum Status 194 { 195 Ok = 200, 196 Created = 201, 197 Accepted = 202, 198 NoContent = 204, 199 ResetContent = 205, 200 PartialContent = 206, 201 202 MultipleChoices = 300, 203 MovedPermanently = 301, 204 MovedTemporarily = 302, 205 NotModified = 304, 206 207 BadRequest = 400, 208 Unauthorized = 401, 209 Forbidden = 403, 210 NotFound = 404, 211 RangeNotSatisfiable = 407, 212 213 InternalServerError = 500, 214 NotImplemented = 501, 215 BadGateway = 502, 216 ServiceNotAvailable = 503, 217 GatewayTimeout = 504, 218 VersionNotSupported = 505, 219 220 InvalidResponse = 1000, 221 ConnectionFailed = 1001 222 223 } 224 225 package sfHttpResponse* sfPtrResponse; 226 227 //Internally used constructor 228 package this(sfHttpResponse* response) 229 { 230 sfPtrResponse = response; 231 } 232 233 ///Get the body of the response. 234 /// 235 ///Returns: The response body. 236 string getBody() 237 { 238 import dsfml.system..string; 239 return dsfml.system..string.toString(sfHttpResponse_getBody(sfPtrResponse)); 240 } 241 242 ///Get the value of a field. 243 /// 244 ///If the field field is not found in the response header, the empty string is returned. This function uses case-insensitive comparisons. 245 /// 246 ///Params: 247 /// field = Name of the field to get. 248 /// 249 ///Returns: Value of the field, or empty string if not found. 250 string getField(string field) 251 { 252 import dsfml.system..string; 253 return dsfml.system..string.toString(sfHttpResponse_getField(sfPtrResponse,toStringz(field))); 254 } 255 256 ///Get the major HTTP version number of the response. 257 /// 258 ///Returns: Major HTTP version number. 259 uint getMajorHttpVersion() 260 { 261 return sfHttpResponse_getMajorVersion(sfPtrResponse); 262 } 263 264 ///Get the minor HTTP version number of the response. 265 /// 266 ///Returns: Minor HTTP version number. 267 uint getMinorHttpVersion() 268 { 269 return sfHttpResponse_getMinorVersion(sfPtrResponse); 270 } 271 272 ///Get the response status code. 273 /// 274 ///The status code should be the first thing to be checked after receiving a response, it defines whether it is a success, a failure or anything else (see the Status enumeration). 275 /// 276 ///Returns: Status code of the response. 277 Status getStatus() 278 { 279 return sfHttpResponse_getStatus(sfPtrResponse); 280 } 281 } 282 } 283 284 unittest 285 { 286 version(DSFML_Unittest_Network) 287 { 288 import std.stdio; 289 290 writeln("Unittest for Http"); 291 292 auto http = new Http(); 293 294 http.setHost("http://www.sfml-dev.org"); 295 296 // Prepare a request to get the 'features.php' page 297 auto request = new Http.Request("learn.php"); 298 299 // Send the request 300 auto response = http.sendRequest(request); 301 302 // Check the status code and display the result 303 auto status = response.getStatus(); 304 305 if (status == Http.Response.Status.Ok) 306 { 307 writeln("Found the site!"); 308 } 309 else 310 { 311 writeln("Error: ", status); 312 } 313 writeln(); 314 } 315 } 316 317 private extern(C): 318 319 struct sfHttpRequest; 320 struct sfHttpResponse; 321 struct sfHttp; 322 323 ///Create a new HTTP request 324 sfHttpRequest* sfHttpRequest_create(); 325 326 327 ///Destroy a HTTP request 328 void sfHttpRequest_destroy(sfHttpRequest* httpRequest); 329 330 331 ///Set the value of a header field of a HTTP request 332 void sfHttpRequest_setField(sfHttpRequest* httpRequest, const(char)* field, const(char)* value); 333 334 335 ///Set a HTTP request method 336 void sfHttpRequest_setMethod(sfHttpRequest* httpRequest, int method); 337 338 339 ///Set a HTTP request URI 340 void sfHttpRequest_setUri(sfHttpRequest* httpRequest, const(char)* uri); 341 342 343 ///Set the HTTP version of a HTTP request 344 void sfHttpRequest_setHttpVersion(sfHttpRequest* httpRequest,uint major, uint minor); 345 346 347 ///Set the body of a HTTP request 348 void sfHttpRequest_setBody(sfHttpRequest* httpRequest, const(char)* ody); 349 350 351 //HTTP Response Functions 352 353 ///Destroy a HTTP response 354 void sfHttpResponse_destroy(sfHttpResponse* httpResponse); 355 356 357 ///Get the value of a field of a HTTP response 358 const(char)* sfHttpResponse_getField(const sfHttpResponse* httpResponse, const(char)* field); 359 360 361 ///Get the status code of a HTTP reponse 362 Http.Response.Status sfHttpResponse_getStatus(const sfHttpResponse* httpResponse); 363 364 365 ///Get the major HTTP version number of a HTTP response 366 uint sfHttpResponse_getMajorVersion(const sfHttpResponse* httpResponse); 367 368 369 ///Get the minor HTTP version number of a HTTP response 370 uint sfHttpResponse_getMinorVersion(const sfHttpResponse* httpResponse); 371 372 373 ///Get the body of a HTTP response 374 const(char)* sfHttpResponse_getBody(const sfHttpResponse* httpResponse); 375 376 377 //HTTP Functions 378 379 ///Create a new Http object 380 sfHttp* sfHttp_create(); 381 382 383 ///Destroy a Http object 384 void sfHttp_destroy(sfHttp* http); 385 386 387 ///Set the target host of a HTTP object 388 void sfHttp_setHost(sfHttp* http, const(char)* host, ushort port); 389 390 391 ///Send a HTTP request and return the server's response. 392 sfHttpResponse* sfHttp_sendRequest(sfHttp* http, const(sfHttpRequest)* request, long timeout);