├── .gitignore ├── SConstruct ├── README.md ├── LICENSE ├── src ├── Common.cpp ├── Request.cpp ├── Headers.cpp ├── Cookie.cpp ├── Response.cpp ├── http.cpp └── Uri.cpp ├── include └── http │ ├── common.hpp │ ├── Error.hpp │ ├── http.hpp │ ├── Headers.hpp │ ├── Request.hpp │ ├── Uri.hpp │ ├── Parse.hpp │ ├── Cookies.hpp │ └── Response.hpp ├── test ├── Get.cpp ├── Api.cpp └── Uri.cpp └── pkgboot.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | .gitattributes 3 | *.slo 4 | *.lo 5 | *.o 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | *.dblite 17 | *.idb 18 | *.pdb 19 | *.pyc 20 | bin 21 | build 22 | lib 23 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | 2 | import pkgboot 3 | 4 | class Http(pkgboot.Package): 5 | defines = {} 6 | includes = [] 7 | libs = [ 8 | 'coro', 9 | pkgboot.Lib('ws2_32', 'win32'), 10 | pkgboot.Lib('advapi32', 'win32'), 11 | pkgboot.Lib('user32', 'win32'), 12 | pkgboot.Lib('gdi32', 'win32'), 13 | 'libeay32', 14 | 'ssleay32', 15 | ] 16 | major_version = '0' 17 | minor_version = '0' 18 | patch = '0' 19 | 20 | Http() 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | http 2 | ==== 3 | 4 | Simple HTTP asynchronous library for modern C++. Depends on [coro](https://github.com/mfichman/coro.git). Here's the basic usage: 5 | 6 | ``` 7 | auto coro = coro::start([]{ 8 | try { 9 | auto res = http::post( 10 | "https://192.168.1.154/user/login", 11 | "{ \"UserId\": \"matt\", \"Password\": \"matt\"} " 12 | ); 13 | 14 | auto sessionId = res.cookie("SessionId"); 15 | std::cout << sessionId.value() << std::endl; 16 | std::cout << sessionId.httpOnly() << std::endl; 17 | std::cout << sessionId.secure() << std::endl; 18 | std::cout << sessionId.path() << std::endl; 19 | } catch (coro::SystemError const& ex) { 20 | std::cerr << ex.what() << std::endl; 21 | } 22 | }); 23 | coro::run(); 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Matt Fichman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | -------------------------------------------------------------------------------- /include/http/common.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef HTTP_COMMON_HPP 24 | #define HTTP_COMMON_HPP 25 | 26 | #include 27 | #include 28 | #include 29 | #undef DELETE // Windows... 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/http/Error.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "http\Common.hpp" 26 | 27 | namespace http { 28 | 29 | class Error { 30 | public: 31 | Error(std::string const& what) : what_(what) {} 32 | 33 | std::string const& what() const { return what_; } 34 | private: 35 | std::string what_; 36 | 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /include/http/http.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "http/Common.hpp" 26 | #include "http/Request.hpp" 27 | #include "http/Response.hpp" 28 | #include "http/Uri.hpp" 29 | 30 | namespace http { 31 | 32 | Response get(std::string const& path, std::string const& data=""); 33 | Response post(std::string const& path, std::string const& data=""); 34 | Response send(Request const& request); 35 | 36 | std::string str(Request const& request); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /test/Get.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/http.hpp" 25 | 26 | int main() { 27 | 28 | auto coro = coro::start([]{ 29 | try { 30 | http::Response res1 = http::get("http://www.google.com"); 31 | assert(res1.status()==http::Response::OK); 32 | http::Response res2 = http::get("https://www.google.com"); 33 | assert(res2.status()==http::Response::OK); 34 | } catch (coro::SystemError const& ex) { 35 | std::cerr << ex.what() << std::endl; 36 | } 37 | }); 38 | coro::run(); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/Request.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/Request.hpp" 25 | 26 | namespace http { 27 | 28 | std::string const Request::header(std::string const& name) const { 29 | return headers_.header(name); 30 | } 31 | 32 | void Request::methodIs(Method method) { 33 | method_ = method; 34 | } 35 | 36 | void Request::uriIs(Uri const& uri) { 37 | uri_ = uri; 38 | } 39 | 40 | void Request::dataIs(std::string const& data) { 41 | data_ = data; 42 | } 43 | 44 | void Request::headerIs(std::string const& name, std::string const& value) { 45 | headers_.headerIs(name, value); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/Headers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/Headers.hpp" 25 | 26 | namespace http { 27 | 28 | std::string const Headers::HOST("Host"); 29 | std::string const Headers::CONTENT_LENGTH("Content-Length"); 30 | std::string const Headers::ACCEPT_ENCODING("Accept-Encoding"); 31 | std::string const Headers::CONNECTION("Connection"); 32 | 33 | std::string const Headers::header(std::string const& name) const { 34 | auto i = header_.find(name); 35 | return (i == header_.end()) ? "" : i->second; 36 | } 37 | 38 | void Headers::headerIs(std::string const& name, std::string const& value) { 39 | header_.emplace(name, value); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /include/http/Headers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "http/Common.hpp" 26 | 27 | namespace http { 28 | 29 | class Headers { 30 | public: 31 | typedef std::multimap Map; 32 | 33 | std::string const header(std::string const& name) const; 34 | Map::const_iterator begin() const { return header_.begin(); } 35 | Map::const_iterator end() const { return header_.end(); } 36 | void headerIs(std::string const& name, std::string const& value); 37 | 38 | static std::string const HOST; 39 | static std::string const CONTENT_LENGTH; 40 | static std::string const ACCEPT_ENCODING; 41 | static std::string const CONNECTION; 42 | private: 43 | Map header_; 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /test/Api.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/http.hpp" 25 | 26 | int main() { 27 | 28 | auto coro = coro::start([]{ 29 | try { 30 | //http::Response res = http::get("https://192.168.1.154/foob"); 31 | // 32 | http::Response res = http::post("https://192.168.1.154/user/login", 33 | "{ \"UserId\": \"matt\", \"Password\": \"matt\"} "); 34 | 35 | auto sessionId = res.cookie("SessionId"); 36 | std::cout << sessionId.value() << std::endl; 37 | std::cout << sessionId.httpOnly() << std::endl; 38 | std::cout << sessionId.secure() << std::endl; 39 | std::cout << sessionId.path() << std::endl; 40 | } catch (coro::SystemError const& ex) { 41 | std::cerr << ex.what() << std::endl; 42 | } 43 | }); 44 | coro::run(); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /include/http/Request.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "http/Common.hpp" 26 | #include "http/Headers.hpp" 27 | #include "http/Uri.hpp" 28 | 29 | namespace http { 30 | 31 | class Request { 32 | public: 33 | enum Method { GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT }; 34 | 35 | Method method() const { return method_; } 36 | Uri const& uri() const { return uri_; } 37 | std::string const& path() const { return uri_.path(); } 38 | std::string const& data() const { return data_; } 39 | std::string const header(std::string const& name) const; 40 | Headers const& headers() const { return headers_; } 41 | 42 | void methodIs(Method method); 43 | void uriIs(Uri const& path); 44 | void dataIs(std::string const& data); 45 | void headerIs(std::string const& name, std::string const& value); 46 | 47 | private: 48 | Method method_ = GET; 49 | Uri uri_; 50 | std::string data_; 51 | Headers headers_; 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /include/http/Uri.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "http/Common.hpp" 26 | 27 | namespace http { 28 | 29 | class Authority { 30 | public: 31 | Authority(std::string const& user, std::string const& host, uint16_t port); 32 | Authority(); 33 | 34 | std::string const& user() const { return user_; } 35 | std::string const& host() const { return host_; } 36 | uint16_t port() const { return port_; } 37 | 38 | void userIs(std::string const& user); 39 | void hostIs(std::string const& host); 40 | void portIs(uint16_t port); 41 | private: 42 | std::string user_; 43 | std::string host_; 44 | uint16_t port_; 45 | }; 46 | 47 | class Uri { 48 | public: 49 | Uri(char* const value); 50 | Uri(std::string const& value); 51 | Uri(); 52 | 53 | std::string const& scheme() const { return scheme_; } 54 | Authority const& authority() const { return authority_; } 55 | std::string const& path() const { return path_; } 56 | std::string const& host() const { return authority_.host(); } 57 | uint16_t port() const { return authority_.port(); } 58 | 59 | void schemeIs(std::string const& scheme); 60 | void authorityIs(Authority const& authority); 61 | void pathIs(std::string const& path); 62 | private: 63 | std::string scheme_; 64 | Authority authority_; 65 | std::string path_; 66 | }; 67 | 68 | } 69 | -------------------------------------------------------------------------------- /include/http/Parse.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | 25 | namespace http { 26 | 27 | template 28 | class ParseResult { 29 | public: 30 | T value; 31 | char const* ch; 32 | }; 33 | 34 | template 35 | static inline ParseResult parseUntil(char const* str, F func) { 36 | ParseResult result{}; 37 | char const* ch = str; 38 | for (; *ch && !func(*ch); ++ch) {} 39 | result.value = std::string(str,ch-str); 40 | result.ch = ch; 41 | return result; 42 | } 43 | 44 | template 45 | static inline ParseResult parseWhile(char const* str, F func) { 46 | ParseResult result{}; 47 | char const* ch = str; 48 | for (; *ch && func(*ch); ++ch) {} 49 | result.value = std::string(str,ch-str); 50 | result.ch = ch; 51 | return result; 52 | } 53 | 54 | static inline ParseResult parseToken(char const* str) { 55 | auto token = parseUntil(str, isspace); 56 | token.ch = parseWhile(token.ch, isspace).ch; 57 | return token; 58 | } 59 | 60 | static inline ParseResult parseCrLf(char const* str) { 61 | auto cr = parseUntil(str, [](char ch) { return ch == '\r'; }); 62 | if (*cr.ch == '\r') { 63 | cr.ch++; 64 | } 65 | return parseWhile(cr.ch, [](char ch) { return isspace(ch) && ch != '\r'; }); 66 | } 67 | 68 | static inline ParseResult parseWhitespace(char const* str) { 69 | return parseWhile(str, isspace); 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /include/http/Cookies.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | namespace http { 24 | 25 | class Cookie { 26 | public: 27 | Cookie(std::string const& text); 28 | Cookie() : httpOnly_(false), secure_(false) {}; 29 | 30 | std::string const& name() const { return name_; } 31 | std::string const& value() const { return value_; } 32 | std::string const& path() const { return path_; } 33 | bool httpOnly() const { return httpOnly_; } 34 | bool secure() const { return secure_; } 35 | 36 | void nameIs(std::string const& name) { name_ = name; } 37 | void valueIs(std::string const& value) { value_ = value; } 38 | void pathIs(std::string const& path) { path_ = path; } 39 | void httpOnlyIs(bool httpOnly) { httpOnly_ = httpOnly; } 40 | void secureIs(bool secure) { secure_ = secure; } 41 | 42 | private: 43 | std::string name_; 44 | std::string value_; 45 | std::string path_; 46 | bool httpOnly_; 47 | bool secure_; 48 | }; 49 | 50 | class Cookies { 51 | public: 52 | typedef std::map Map; 53 | 54 | Cookie const cookie(std::string const& name) const; 55 | Map::const_iterator begin() const { return cookie_.begin(); } 56 | Map::const_iterator end() const { return cookie_.end(); } 57 | 58 | void cookieIs(Cookie const& cookie); 59 | 60 | static std::string const HOST; 61 | static std::string const CONTENT_LENGTH; 62 | static std::string const ACCEPT_ENCODING; 63 | static std::string const CONNECTION; 64 | private: 65 | Map cookie_; 66 | }; 67 | 68 | } 69 | -------------------------------------------------------------------------------- /test/Uri.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "http/http.hpp" 25 | 26 | void simple() { 27 | http::Uri uri("http://www.google.com:80/foo/bar.html"); 28 | assert(uri.scheme()=="http"); 29 | assert(uri.authority().host()=="www.google.com"); 30 | assert(uri.authority().port()==80); 31 | assert(uri.path()=="/foo/bar.html"); 32 | } 33 | 34 | void user() { 35 | http::Uri uri("http://user@www.google.com:80/foo/bar.html"); 36 | assert(uri.scheme()=="http"); 37 | assert(uri.authority().user()=="user"); 38 | assert(uri.authority().host()=="www.google.com"); 39 | assert(uri.authority().port()==80); 40 | assert(uri.path()=="/foo/bar.html"); 41 | } 42 | 43 | void noPort() { 44 | http::Uri uri("http://user@www.google.com/foo/bar.html"); 45 | assert(uri.scheme()=="http"); 46 | assert(uri.authority().user()=="user"); 47 | assert(uri.authority().host()=="www.google.com"); 48 | assert(uri.authority().port()==0); 49 | assert(uri.path()=="/foo/bar.html"); 50 | } 51 | 52 | void noHost() { 53 | http::Uri uri("file:///foo/bar.html"); 54 | assert(uri.scheme()=="file"); 55 | assert(uri.authority().user()==""); 56 | assert(uri.authority().host()==""); 57 | assert(uri.authority().port()==0); 58 | assert(uri.path()=="/foo/bar.html"); 59 | } 60 | 61 | void fragment() { 62 | http::Uri uri("file:///foo/bar.html?foo=bar#foo"); 63 | assert(uri.scheme()=="file"); 64 | assert(uri.authority().user()==""); 65 | assert(uri.authority().host()==""); 66 | assert(uri.authority().port()==0); 67 | assert(uri.path()=="/foo/bar.html?foo=bar#foo"); 68 | } 69 | 70 | int main() { 71 | simple(); 72 | user(); 73 | noPort(); 74 | noHost(); 75 | fragment(); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /src/Cookie.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/Cookies.hpp" 25 | #include "http/Parse.hpp" 26 | 27 | namespace http { 28 | 29 | ParseResult parseName(char const* str) { 30 | return parseUntil(str, [](char ch) { return isspace(ch) || ch == '='; }); 31 | } 32 | 33 | ParseResult parseValue(char const* str) { 34 | return parseUntil(str, [](char ch) { return ch == ';' || ch == '='; }); 35 | } 36 | 37 | ParseResult parseSeparator(char const* str) { 38 | if (*str) { 39 | assert(*str==';'||*str=='='); 40 | return parseWhitespace(str+1); 41 | } else { 42 | auto result = ParseResult{}; 43 | result.ch = str; 44 | return result; 45 | } 46 | } 47 | 48 | Cookie parseCookie(char const* str) { 49 | auto name = parseName(str); 50 | auto ch = parseSeparator(name.ch).ch; 51 | auto value = parseValue(ch); 52 | ch = parseSeparator(value.ch).ch; 53 | 54 | auto cookie = Cookie(); 55 | cookie.nameIs(name.value); 56 | cookie.valueIs(value.value); 57 | while (*ch) { 58 | auto flag = parseValue(ch); 59 | if (flag.value == "Path") { 60 | ch = parseSeparator(flag.ch).ch; 61 | flag = parseValue(ch); 62 | cookie.pathIs(flag.value); 63 | } else if (flag.value == "HttpOnly") { 64 | cookie.httpOnlyIs(true); 65 | } else if (flag.value == "Secure") { 66 | cookie.secureIs(true); 67 | } 68 | ch = parseSeparator(flag.ch).ch; 69 | } 70 | return cookie; 71 | } 72 | 73 | Cookie::Cookie(std::string const& text) { 74 | *this = parseCookie(text.c_str()); 75 | } 76 | 77 | Cookie const Cookies::cookie(std::string const& name) const { 78 | auto i = cookie_.find(name); 79 | return (i == cookie_.end()) ? Cookie() : i->second; 80 | } 81 | 82 | void Cookies::cookieIs(Cookie const& cookie) { 83 | cookie_[cookie.name()] = cookie; 84 | } 85 | 86 | } 87 | 88 | -------------------------------------------------------------------------------- /include/http/Response.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "http/Common.hpp" 26 | #include "http/Headers.hpp" 27 | #include "http/Cookies.hpp" 28 | 29 | namespace http { 30 | 31 | class Response { 32 | public: 33 | enum Status { 34 | INVALID_CODE = 0, 35 | CONTINUE = 100, 36 | SWITCHING_PROTOCOLS = 101, 37 | OK = 200, 38 | CREATED = 201, 39 | ACCEPTED = 202, 40 | NON_AUTHORITATIVE_INFO = 203, 41 | NO_CONTENT = 204, 42 | RESET_CONTENT = 205 , 43 | PARTIAL_CONTENT = 206, 44 | MULTIPLE_CHOICES = 300, 45 | MOVED_PERMANENTLY = 301, 46 | FOUND = 302, 47 | SEE_OTHER = 303, 48 | NOT_MODIFIED = 304, 49 | USE_PROXY = 305, 50 | TEMPORARY_REDIRECT = 307, 51 | BAD_REQUEST = 400, 52 | UNAUTHORIZED = 401, 53 | PAYMENT_REQUIRED = 402 , 54 | FORBIDDEN = 403, 55 | NOT_FOUND = 404, 56 | METHOD_NOT_ALLOWED = 405, 57 | NOT_ACCEPTABLE = 406, 58 | PROXY_AUTHENTICATION_REQUIRED = 407, 59 | REQUEST_TIMEOUT = 408, 60 | CONFLICT = 409, 61 | GONE = 410, 62 | LENGTH_REQUIRED = 411, 63 | PRECONDITION_FAILED = 412, 64 | REQUEST_ENTITY_TOO_LARGE = 413, 65 | UNSUPPORTED_MEDIA_TYPE = 415, 66 | REQUESTED_RANGE_NOT_SATISFIABLE = 416, 67 | EXPECTATION_FAILED = 417, 68 | INTERNAL_SERVER_ERROR = 500, 69 | NOT_IMPLEMENTED = 501, 70 | BAD_GATEWAY = 502, 71 | SERVICE_UNAVAILABLE = 503, 72 | GATEWAY_TIMEOUT = 504, 73 | VERSION_NOT_SUPPORTED = 505, 74 | }; 75 | 76 | Response(std::string const& text); 77 | Response() {}; 78 | 79 | Status status() const { return status_; } 80 | std::string const& data() const { return data_; } 81 | std::string const header(std::string const& name) const; 82 | Cookie const cookie(std::string const& name) const; 83 | 84 | void statusIs(Status status); 85 | void versionIs(std::string const& version); 86 | void dataIs(std::string const& data); 87 | void headerIs(std::string const& name, std::string const& value); 88 | void cookieIs(Cookie const& cookie); 89 | 90 | private: 91 | Status status_ = INVALID_CODE; 92 | std::string data_; 93 | Headers headers_; 94 | Cookies cookies_; 95 | }; 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/Response.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/Response.hpp" 25 | #include "http/Error.hpp" 26 | #include "http/Parse.hpp" 27 | 28 | namespace http { 29 | 30 | static ParseResult parseStatus(char const* str) { 31 | ParseResult result{}; 32 | auto code = parseToken(str); 33 | 34 | result.value = (Response::Status)std::atoi(code.value.c_str()); 35 | result.ch = code.ch; 36 | return result; 37 | } 38 | 39 | Response parseResponse(char const* str) { 40 | // Parse an HTTP response 41 | auto version = parseToken(str); 42 | auto code = parseStatus(version.ch); 43 | auto message = parseUntil(code.ch, [](char ch) { return ch == '\r'; }); 44 | 45 | auto response = Response(); 46 | if (version.value != "HTTP/1.1") { 47 | throw Error("bad HTTP version"); 48 | } 49 | 50 | auto ch = parseCrLf(message.ch).ch; 51 | while (*ch != '\0' && *ch != '\r') { 52 | auto name = parseUntil(ch, [](char ch) { return ch == ':'; }); 53 | if (*name.ch) { 54 | name.ch++; // For ":" 55 | } 56 | auto ws = parseWhile(name.ch, isspace); 57 | auto value = parseUntil(ws.ch, [](char ch) { return ch == '\r'; }); 58 | response.headerIs(name.value, value.value); 59 | if (name.value == "Set-Cookie") { 60 | response.cookieIs(Cookie(value.value)); 61 | } 62 | ch = parseCrLf(value.ch).ch; 63 | } 64 | ch = parseCrLf(ch).ch; 65 | 66 | response.statusIs(code.value); 67 | response.dataIs(ch); 68 | return response; 69 | } 70 | 71 | Response::Response(std::string const& response) { 72 | *this = parseResponse(response.c_str()); 73 | } 74 | 75 | std::string const Response::header(std::string const& name) const { 76 | return headers_.header(name); 77 | } 78 | 79 | Cookie const Response::cookie(std::string const& name) const { 80 | return cookies_.cookie(name); 81 | } 82 | 83 | void Response::statusIs(Status status) { 84 | status_ = status; 85 | } 86 | 87 | void Response::dataIs(std::string const& data) { 88 | data_ = data; 89 | } 90 | 91 | void Response::headerIs(std::string const& name, std::string const& value) { 92 | headers_.headerIs(name, value); 93 | } 94 | 95 | void Response::cookieIs(Cookie const& cookie) { 96 | cookies_.cookieIs(cookie); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/http.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/http.hpp" 25 | 26 | namespace http { 27 | 28 | Response send(Request const& request) { 29 | // Send an HTTP request. Auto-fill the content-length headers. 30 | std::string const string = str(request); 31 | 32 | uint16_t port = 0; 33 | coro::Ptr sd; 34 | if (request.uri().scheme() == "https") { 35 | sd.reset(new coro::SslSocket); 36 | port = 443; 37 | } else if (request.uri().scheme() == "http") { 38 | sd.reset(new coro::Socket); 39 | port = 80; 40 | } else { 41 | assert(!"unknown http scheme"); 42 | } 43 | if (request.uri().port()) { 44 | port = request.uri().port(); 45 | } 46 | sd->connect(coro::SocketAddr(request.uri().host(), port)); 47 | sd->writeAll(string.c_str(), string.size()); 48 | 49 | std::vector buffer(16384); // 16 KiB 50 | std::stringstream ss; 51 | 52 | while (size_t bytes = sd->read(&buffer[0], buffer.size())) { 53 | ss.write(&buffer[0], bytes); 54 | } 55 | 56 | return Response(ss.str()); 57 | } 58 | 59 | Response get(std::string const& path, std::string const& data) { 60 | // Shortcut for simple GET requests 61 | Request request; 62 | request.methodIs(Request::GET); 63 | request.uriIs(Uri(path)); 64 | request.dataIs(data); 65 | return send(request); 66 | } 67 | 68 | Response post(std::string const& path, std::string const& data) { 69 | // Shortcut for simple POST requests 70 | Request request; 71 | request.methodIs(Request::POST); 72 | request.uriIs(Uri(path)); 73 | request.dataIs(data); 74 | return send(request); 75 | } 76 | 77 | std::string str(Request::Method method) { 78 | switch (method) { 79 | case Request::GET: return "GET"; 80 | case Request::HEAD: return "HEAD"; 81 | case Request::POST: return "POST"; 82 | case Request::PUT: return "PUT"; 83 | case Request::DELETE: return "DELETE"; 84 | case Request::TRACE: return "TRACE"; 85 | case Request::CONNECT: return "CONNECT"; 86 | default: assert(!"unknown request method"); 87 | } 88 | return ""; 89 | } 90 | 91 | std::string str(Request const& request) { 92 | // Serialize a request to a string 93 | std::stringstream ss; 94 | auto path = request.path().empty() ? "/" : request.path(); 95 | ss << str(request.method()) << ' ' << path << " HTTP/1.1\n"; 96 | ss << Headers::HOST << ": " << request.uri().host() << "\n"; 97 | ss << Headers::CONTENT_LENGTH << ": " << request.data().size() << "\n"; 98 | ss << Headers::CONNECTION << ": close\n"; 99 | ss << Headers::ACCEPT_ENCODING << ": identity\n"; 100 | for(auto header : request.headers()) { 101 | ss << header.first << ": " << header.second << "\n"; 102 | } 103 | ss << "\n"; 104 | ss << request.data(); 105 | return ss.str(); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/Uri.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Matt Fichman 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include "http/Common.hpp" 24 | #include "http/Uri.hpp" 25 | #include "http/Parse.hpp" 26 | 27 | namespace http { 28 | 29 | static bool isReserved(char ch) { 30 | switch (ch) { 31 | case '/': return true; 32 | case '#': return true; 33 | case '?': return true; 34 | default: return false; 35 | } 36 | } 37 | 38 | static ParseResult parseScheme(char const* str) { 39 | auto result = parseWhile(str, [](char ch) { 40 | return ch != ':' && !isReserved(ch); 41 | }); 42 | result.ch = (result.ch[0] == ':') ? (result.ch+1) : (result.ch); 43 | return result; 44 | } 45 | 46 | static ParseResult parseUser(char const* str) { 47 | auto result = parseWhile(str, [](char ch) { 48 | return ch != '@' && !isReserved(ch); 49 | }); 50 | if (result.ch[0] == '@') { 51 | result.ch = result.ch+1; 52 | } else { 53 | result.ch = str; 54 | result.value = ""; 55 | } 56 | return result; 57 | } 58 | 59 | static ParseResult parseHost(char const* str) { 60 | return parseWhile(str, [](char ch) { 61 | return ch != ':' && !isReserved(ch); 62 | }); 63 | } 64 | 65 | static ParseResult parsePort(char const* str) { 66 | ParseResult result; 67 | if (str[0] != ':') { 68 | result.value = 0; 69 | result.ch = str; 70 | return result; 71 | } 72 | auto tmp = parseWhile(str+1, [](char ch) { 73 | return !isReserved(ch); 74 | }); 75 | result.value = uint16_t(strtol(tmp.value.c_str(), 0, 10)); 76 | result.ch = tmp.ch; 77 | return result; 78 | } 79 | 80 | static ParseResult parseAuthority(char const* str) { 81 | ParseResult result{}; 82 | if (str[0] == '\0' || str[0] != '/' || str[1] != '/') { 83 | result.ch = str; 84 | return result; 85 | } 86 | 87 | auto user = parseUser(str+2); // For "//" 88 | auto host = parseHost(user.ch); 89 | auto port = parsePort(host.ch); 90 | 91 | result.value.userIs(user.value); 92 | result.value.hostIs(host.value); 93 | result.value.portIs(port.value); 94 | result.ch = port.ch; 95 | 96 | return result; 97 | } 98 | 99 | static ParseResult parsePath(char const* str) { 100 | // Return query/frag as part of path for now 101 | ParseResult result = parseWhile(str, [](char ch) { 102 | return true; 103 | }); 104 | /* 105 | ParseResult result = parseWhile(str, [](char ch) { 106 | return ch != '/' && !isReserved(ch); 107 | }); 108 | result.ch = (result.ch[0] == '?') ? (result.ch+1) : (result.ch); 109 | */ 110 | return result; 111 | 112 | } 113 | 114 | static Uri parseUri(char const* str) { 115 | Uri uri; 116 | 117 | auto scheme = parseScheme(str); 118 | auto authority = parseAuthority(scheme.ch); 119 | auto path = parsePath(authority.ch); 120 | 121 | uri.schemeIs(scheme.value); 122 | uri.authorityIs(authority.value); 123 | uri.pathIs(path.value); 124 | return uri; 125 | } 126 | 127 | 128 | Authority::Authority(std::string const& user, std::string const& host, uint16_t port) { 129 | user_ = user; 130 | host_ = host; 131 | port_ = port; 132 | } 133 | 134 | Authority::Authority() { 135 | port_ = 0; 136 | } 137 | 138 | void Authority::userIs(std::string const& user) { 139 | user_ = user; 140 | } 141 | 142 | void Authority::hostIs(std::string const& host) { 143 | host_ = host; 144 | } 145 | 146 | void Authority::portIs(uint16_t port) { 147 | port_ = port; 148 | } 149 | 150 | Uri::Uri(char* const value) { 151 | *this = parseUri(value); 152 | } 153 | 154 | Uri::Uri(std::string const& value) { 155 | *this = parseUri(value.c_str()); 156 | } 157 | 158 | Uri::Uri() { 159 | } 160 | 161 | void Uri::schemeIs(std::string const& scheme) { 162 | scheme_ = scheme; 163 | } 164 | 165 | void Uri::authorityIs(Authority const& authority) { 166 | authority_ = authority; 167 | } 168 | 169 | void Uri::pathIs(std::string const& path) { 170 | path_ = path; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /pkgboot.py: -------------------------------------------------------------------------------- 1 | 2 | import platform 3 | import os 4 | import sys 5 | import shutil 6 | import subprocess 7 | import shlex 8 | import glob 9 | 10 | try: 11 | from SCons.Script import * 12 | except ImportError: 13 | pass 14 | 15 | def run_test(target, source, env): 16 | # Runs a single unit test and checks that the return code is 0 17 | try: 18 | subprocess.check_call(source[0].abspath) 19 | except subprocess.CalledProcessError, e: 20 | return 1 21 | 22 | def build_pch(target, source, env): 23 | try: 24 | args = ( 25 | str(env['CXX']), 26 | str(env['CXXFLAGS']), 27 | ' '.join('-I%s' % path for path in env['CPPPATH']), 28 | '-x', 29 | 'c++-header', 30 | str(source[0]), 31 | '-o', 32 | str(target[0]), 33 | ) 34 | print(' '.join(args)) 35 | subprocess.check_call(shlex.split(' '.join(args))) 36 | except subprocess.CalledProcessError, e: 37 | return 1 38 | 39 | class Lib: 40 | """ 41 | Defines a library that the build depends upon. 42 | """ 43 | def __init__(self, name, platforms): 44 | self.name = name 45 | self.platforms = platforms 46 | 47 | def __str__(self): 48 | return self.name 49 | 50 | def __repr__(self): 51 | return self.name 52 | 53 | class Package: 54 | """ 55 | Defines a workspace for a package. Automatically sets up all the usual SCons 56 | stuff, including a precompiled header file. 57 | """ 58 | defines = {} 59 | includes = [] 60 | libs = [] 61 | frameworks = [] 62 | path = [] 63 | lib_path = [] 64 | major_version = '0' 65 | minor_version = '0' 66 | patch = '0' 67 | kind = 'lib' 68 | frameworks = [] 69 | assets = [] 70 | 71 | def __init__(self): 72 | # Initializes a package, and sets up an SCons build environment given 73 | # the instructions found in the subclass definition. 74 | self._setup_vars() 75 | self._setup_env() 76 | self._setup_assets() 77 | if self.env['PLATFORM'] == 'win32': 78 | self._setup_win() 79 | else: 80 | self._setup_unix() 81 | self._setup_tests() 82 | self.build() # Run custom code for building the package 83 | 84 | def _lib_is_valid_for_platform(self, lib): 85 | if type(lib) == str: 86 | return True 87 | elif type(lib.platforms) == list: 88 | return self.env['PLATFORM'] in lib.platforms 89 | elif type(lib.platforms) == str: 90 | return self.env['PLATFORM'] == lib.platforms 91 | 92 | def _setup_assets(self): 93 | if len(self.assets) <= 0: 94 | return 95 | 96 | fd = open('include/%s/Assets.hpp' % self.name, 'w') 97 | fd.write('#pragma once\n') 98 | fd.write('namespace %s {\n' % self.name) 99 | fd.write('struct Asset {\n') 100 | fd.write(' char const* name;\n') 101 | fd.write(' char const* data;\n') 102 | fd.write(' size_t len;\n') 103 | fd.write('};\n') 104 | fd.write('extern Asset const assets[];\n') 105 | fd.write('}\n') 106 | fd.close() 107 | 108 | fd = open('src/Assets.cpp', 'w') 109 | fd.write('#include "%s/Common.hpp"\n' % self.name) 110 | fd.write('#include "%s/Assets.hpp"\n' % self.name) 111 | fd.write('namespace %s {\n' % self.name) 112 | fd.write('extern Asset const assets[] = {\n') 113 | for pattern in self.assets: 114 | for fn in glob.glob(pattern): 115 | fn = fn.replace('\\', '/') # Windows!! 116 | fd.write('{"%s",' % fn) 117 | r = open(fn, 'rb') # Windows!!! (binary mode required) 118 | data = r.read() 119 | length = len(data) 120 | data = ''.join(['\\x%02x' % ord(ch) for ch in data]) 121 | fd.write('"%s",%d},\n' % (data, length)) 122 | fd.write('{0, 0, 0},') 123 | fd.write('};\n') 124 | fd.write('}\n') 125 | fd.close() 126 | 127 | 128 | def _setup_vars(self): 129 | # Set up the basic configuration options 130 | (system, _, release, version, machine, proc) = platform.uname() 131 | self.name = self.__class__.__name__.lower() 132 | self.pch = '%s/Common.hpp' % self.name 133 | self.build_mode = ARGUMENTS.get('mode', 'debug') 134 | self.version = '.'.join((self.major_version, self.minor_version, self.patch)) 135 | self.branch = os.popen('git rev-parse --abbrev-ref HEAD').read().strip() 136 | self.revision = os.popen('git rev-parse HEAD').read().strip() 137 | self.defines.update({ 138 | 'VERSION': self.version, 139 | 'REVISION': self.revision, 140 | 'BRANCH': self.branch, 141 | }) 142 | self.includes.extend([ 143 | 'include', 144 | 'src', 145 | ]) 146 | self.src = [] 147 | 148 | def _setup_env(self): 149 | # Create the SCons build environment, and fill it with default parameters. 150 | self.env = Environment(CPPPATH=['build/src']) 151 | self.env.Append(ENV=os.environ) 152 | self.env.VariantDir('build/src', 'src', duplicate=0) 153 | self.env.VariantDir('build/test', 'test', duplicate=0) 154 | 155 | def _setup_win(self): 156 | # Set up Windows-specific options 157 | if self.build_mode == 'debug': 158 | pass 159 | elif self.build_mode == 'release': 160 | self.env.Append(CXXFLAGS='/O2') 161 | else: 162 | assert not "Unknown build type" 163 | self.env.Append(CXXFLAGS='/W4 /WX /wd4100 /MT /EHsc /Zi /Gm /FS') 164 | self.env.Append(CXXFLAGS='/Fpbuild/Common.pch') 165 | self.env.Append(CXXFLAGS='/Yu%s' % self.pch) 166 | self.env.Append(LINKFLAGS='/DEBUG') 167 | self.src += self.env.Glob('build/src/**.asm') 168 | # Add MASM assembly files 169 | 170 | self.includes.extend([ 171 | 'C:\\WinBrew\\include', 172 | ]) 173 | self.lib_path.extend([ 174 | 'C:\\WinBrew\\lib', 175 | ]) 176 | self.path.extend([ 177 | os.environ['PATH'], 178 | 'C:\\WinBrew\\lib', 179 | 'C:\\WinBrew\\bin', 180 | ]) 181 | # Extra Windows includes 182 | 183 | self._setup_build() 184 | 185 | pchenv = self.env.Clone() 186 | pchenv.Append(CXXFLAGS='/Yc%s' % self.pch) 187 | self.pch = pchenv.StaticObject('build/src/Common', 'build/src/Common.cpp') 188 | 189 | self._finish_build() 190 | 191 | def _setup_unix(self): 192 | # Set up OS X/Linux-specific options 193 | if self.build_mode == 'debug': 194 | self.env.Append(CXXFLAGS='-O0') 195 | elif self.build_mode == 'release': 196 | self.env.Append(CXXFLAGS='-O2') 197 | else: 198 | assert not "Unknown build type" 199 | 200 | self.env['CXX'] = 'clang++' 201 | self.env.Append(CXXFLAGS='-std=c++11 -stdlib=libc++ -g -Wall -Werror -fPIC') 202 | for framework in self.frameworks: 203 | self.env.Append(LINKFLAGS='-framework %s' % framework) 204 | self.env.Append(LINKFLAGS='-stdlib=libc++') 205 | self.env.Append(BUILDERS={'Pch': Builder(action=build_pch)}) 206 | self.src += self.env.Glob('build/src/**.s') 207 | # Add gas assembly files 208 | 209 | self._setup_build() 210 | 211 | pchenv = self.env.Clone() 212 | self.pch = pchenv.Pch('include/%s/Common.hpp.pch' % self.name, 'include/%s' % self.pch) 213 | self.env.Append(CXXFLAGS='-include include/%s/Common.hpp' % self.name) 214 | 215 | self._finish_build() 216 | 217 | def _setup_build(self): 218 | # Set up the basic build options 219 | self.libs = filter(self._lib_is_valid_for_platform, self.libs) 220 | self.libs = map(str, self.libs) 221 | 222 | self.env.Append(CPPDEFINES=self.defines) 223 | self.env.Append(CPPPATH=self.includes) 224 | self.env.Append(LIBPATH=self.lib_path) 225 | self.env.Append(LIBS=self.libs) 226 | 227 | self.src += self.env.Glob('build/src/**.cpp') 228 | self.src += self.env.Glob('build/src/**.c') 229 | self.src = filter(lambda x: 'Common.cpp' not in x.name, self.src) 230 | self.env.Depends(self.src, self.pch) # Wait for pch to build 231 | 232 | def _finish_build(self): 233 | if self.env['PLATFORM'] == 'win32': 234 | self.lib = self.env.StaticLibrary('lib/%s' % self.name, (self.src, self.pch)) 235 | else: 236 | self.lib = self.env.SharedLibrary('lib/%s' % self.name, self.src) 237 | if self.kind == 'bin': 238 | main = self.env.Glob('Main.cpp') 239 | self.program = self.env.Program('bin/%s' % self.name, (self.lib, main)) 240 | for tool in glob.glob('tools/*.cpp'): 241 | name = os.path.splitext(os.path.basename(tool.lower()))[0] 242 | self.env.Program('bin/%s-%s' % (self.name, name), (self.lib, tool)) 243 | 244 | def _setup_tests(self): 245 | # Configure the test environment 246 | self.env.Append(BUILDERS={'Test': Builder(action=run_test)}) 247 | self.tests = [] 248 | testenv = self.env.Clone() 249 | testenv.Append(LIBS=self.lib) 250 | for test in self.env.Glob('build/test/**.cpp'): 251 | self.env.Depends(test, self.pch) 252 | name = test.name.replace('.cpp', '') 253 | if self.env['PLATFORM'] == 'win32': 254 | inputs = (test, self.pch) 255 | else: 256 | inputs = (test,) 257 | prog = testenv.Program('bin/test/%s' % name, inputs) 258 | if 'check' in COMMAND_LINE_TARGETS: 259 | self.tests.append(testenv.Test(name, prog)) 260 | if 'check' in COMMAND_LINE_TARGETS: 261 | self.env.Alias('check', self.tests) 262 | 263 | def build(self): 264 | pass 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | --------------------------------------------------------------------------------