2 * ______________________________________
4 * | | \ | |/ |/ | Date: 06/23/2022 |
5 * | | \| |- |- | Author: Levi Hicks |
8 * | |_| \_||_||_| File: Link.cpp |
11 * | Please do not remove this header. |
12 * |______________________________________|
15 #include "../Includes/Link/Link.hpp"
18 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
35 #include <bits/stdc++.h>
36 #include "../Includes/Link/HTTPTools.hpp"
39 * Holds data for the request.
43 std::function
<void(Request
*, Response
*)> func
;
45 std::map
<int, std::function
<void(Request
*, Response
*)>> errorHandlers
;
49 * Creates a new thread.
50 * We have to use this because pthread_create will not hold the function and the Request.
52 * @param info The information to pass to the thread.
54 void* threadWrapper(void* arg
) {
55 ThreadInfo
* info
= (ThreadInfo
*)arg
;
56 Response
response(info
->request
, &info
->errorHandlers
);
57 info
->func(info
->request
, &response
);
58 if (!response
.IsCancelled()) {
60 while (packet
< response
.GetHTTP().size()) {
61 int packetLength
= response
.GetHTTP().size()<packet
+1024? response
.GetHTTP().size()-packet
: 1024;
62 std::string PacketData
= response
.GetHTTP().substr(packet
, packetLength
);
63 int sent
= send(info
->request
->GetSocket(), PacketData
.c_str(), PacketData
.size(), 0);
64 if (sent
< 0) return NULL
;
67 close(info
->request
->GetSocket());
69 close(info
->request
->GetSocket());
75 * Creates a Link server
77 * @param port The port that the server will run on.
79 Link::Link(int port
) { this->port
= port
; }
82 * Set handler for a get request.
84 * @param path The specific path for the handler.
85 * @param callback The function to call when a get request is made.
87 void Link::Get(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
88 this->handlers
[path
+"GET"] = callback
;
92 * Sets default request handler.
94 * @param callback The function to call when a request is made.
96 void Link::Default(std::function
<void(Request
*, Response
*)> callback
) {
97 this->defaultHandler
= callback
;
101 * Set handler for a post request.
103 * @param path The specific path for the handler.
104 * @param callback The function to call when a post request is made.
106 void Link::Post(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
107 this->handlers
[path
+"POST"] = callback
;
111 * Set handler for a put request.
113 * @param path The specific path for the handler.
114 * @param callback The function to call when a put request is made.
116 void Link::Put(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
117 this->handlers
[path
+"PUT"] = callback
;
121 * Set handler for a delete request.
123 * @param path The specific path for the handler.
124 * @param callback The function to call when a delete request is made.
126 void Link::Delete(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
127 this->handlers
[path
+"DELETE"] = callback
;
131 * Set handler for an error.
133 * @param code The error code.
134 * @param callback The function to call when an error is made.
136 void Link::Error(int code
, std::function
<void(Request
*, Response
*)> callback
) {
137 this->errorHandlers
[code
] = callback
;
141 * Binds and listens on specified port
143 * @return the error code.
146 this->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
147 if (this->sock
== 0) return 1;
149 if (setsockopt(this->sock
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) < 0) return 2;
150 int time
= 7200, interval
= 60, retry
= 3;
151 struct sockaddr_in addr
;
152 addr
.sin_family
= AF_INET
;
153 addr
.sin_addr
.s_addr
= INADDR_ANY
;
154 addr
.sin_port
= htons(this->port
);
155 if (bind(this->sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) return 3;
156 if (listen(this->sock
, 50) < 0) return 4;
158 char buffer
[1024] = {0};
159 struct sockaddr_in addr
;
160 socklen_t addrSize
= sizeof(addr
);
161 int sock
= accept(this->sock
, (struct sockaddr
*)&addr
, &addrSize
);
162 recv(sock
, buffer
, 1024, 0);
163 std::string bufferStr
= buffer
, line
, path
, method
;
164 std::map
<std::string
, std::string
> queriesMap
;
165 std::istringstream
stream(decodeHTTP(bufferStr
));
166 getline(stream
, line
);
167 if (line
.substr(0, 3) == "GET" || line
.substr(0, 4) == "POST" || line
.substr(0, 3) == "PUT" || line
.substr(0, 6) == "DELETE") {
168 method
= line
.substr(0, 3) == "GET" ? "GET" : line
.substr(0, 4) == "POST" ? "POST" : line
.substr(0, 3) == "PUT"? "PUT" : "DELETE";
169 path
= line
.substr(method
.length()+1);
170 path
= path
.substr(0, path
.find_last_of("HTTP/1.1")-8);
175 if (path
.find("?") != std::string::npos
) {
176 std::string queries
= path
.substr(path
.find_last_of("?")+1);
177 path
= path
.substr(0, path
.find_last_of("?"));
178 std::istringstream
stream(queries
);
180 while(getline(stream
, query
, '&')) {
181 std::string key
= query
.substr(0, query
.find_first_of("="));
182 std::string value
= query
.substr(query
.find_first_of("=")+1);
183 queriesMap
[key
] = sanitize(value
);
185 std::string newPath
= "";
186 for (int i
=0; i
<path
.length(); i
++) if (path
.substr(i
, 2) != "//") newPath
+= path
[i
];
187 path
= newPath
[newPath
.length()-1]=='/' ? newPath
.substr(0, newPath
.length()-1) : newPath
;
189 Request
request(sock
, &addr
, path
, method
, buffer
, queriesMap
);
190 if (this->handlers
.contains(path
+method
)) {
191 ThreadInfo
* info
= new ThreadInfo();
192 info
->func
= this->handlers
.find(path
+method
)->second
;
193 info
->request
= &request
;
194 info
->errorHandlers
= this->errorHandlers
;
196 pthread_create(&thread
, NULL
, threadWrapper
, info
);
197 pthread_join(thread
, NULL
);
198 } else if (this->defaultHandler
!= nullptr) {
199 ThreadInfo
* info
= new ThreadInfo();
200 info
->func
= this->defaultHandler
;
201 info
->request
= &request
;
202 info
->errorHandlers
= this->errorHandlers
;
204 pthread_create(&thread
, NULL
, threadWrapper
, info
);
205 pthread_join(thread
, NULL
);
208 shutdown(this->sock
, SHUT_RDWR
);
216 * Shuts down the server
218 * @return the error code.
221 return shutdown(this->sock
, SHUT_RDWR
);
226 * @return the port number
228 int Link::GetPort() { return this->port
; }