You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

http.h 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef HTTP_H_
  17. #define HTTP_H_
  18. /**
  19. * @file http.h
  20. *
  21. * This is an interface for HTTP client and conn. This code uses HTTP parser written
  22. * by Joyent Inc based on nginx code.
  23. */
  24. #include "config.h"
  25. #include "http_parser.h"
  26. #include "keypair.h"
  27. #include "keypairs_cache.h"
  28. #include "fstring.h"
  29. #include "ref.h"
  30. enum rspamd_http_connection_type {
  31. RSPAMD_HTTP_SERVER,
  32. RSPAMD_HTTP_CLIENT
  33. };
  34. struct rspamd_http_header;
  35. struct rspamd_http_message;
  36. struct rspamd_http_connection_private;
  37. struct rspamd_http_connection;
  38. struct rspamd_http_connection_router;
  39. struct rspamd_http_connection_entry;
  40. struct rspamd_storage_shmem {
  41. gchar *shm_name;
  42. ref_entry_t ref;
  43. };
  44. /**
  45. * Legacy spamc protocol
  46. */
  47. #define RSPAMD_HTTP_FLAG_SPAMC (1 << 0)
  48. /**
  49. * Store body of the message in a shared memory segment
  50. */
  51. #define RSPAMD_HTTP_FLAG_SHMEM (1 << 2)
  52. /**
  53. * Store body of the message in an immutable shared memory segment
  54. */
  55. #define RSPAMD_HTTP_FLAG_SHMEM_IMMUTABLE (1 << 3)
  56. /**
  57. * Use tls for this message
  58. */
  59. #define RSPAMD_HTTP_FLAG_SSL (1 << 4)
  60. /**
  61. * Body has been set for a message
  62. */
  63. #define RSPAMD_HTTP_FLAG_HAS_BODY (1 << 5)
  64. /**
  65. * Do not verify server's certificate
  66. */
  67. #define RSPAMD_HTTP_FLAG_SSL_NOVERIFY (1 << 6)
  68. /**
  69. * Options for HTTP connection
  70. */
  71. enum rspamd_http_options {
  72. RSPAMD_HTTP_BODY_PARTIAL = 0x1, /**< Call body handler on all body data portions *///!< RSPAMD_HTTP_BODY_PARTIAL
  73. RSPAMD_HTTP_CLIENT_SIMPLE = 0x1u << 1, /**< Read HTTP client reply automatically */ //!< RSPAMD_HTTP_CLIENT_SIMPLE
  74. RSPAMD_HTTP_CLIENT_ENCRYPTED = 0x1u << 2, /**< Encrypt data for client */ //!< RSPAMD_HTTP_CLIENT_ENCRYPTED
  75. RSPAMD_HTTP_CLIENT_SHARED = 0x1u << 3, /**< Store reply in shared memory */ //!< RSPAMD_HTTP_CLIENT_SHARED
  76. RSPAMD_HTTP_REQUIRE_ENCRYPTION = 0x1u << 4
  77. };
  78. typedef int (*rspamd_http_body_handler_t) (struct rspamd_http_connection *conn,
  79. struct rspamd_http_message *msg,
  80. const gchar *chunk,
  81. gsize len);
  82. typedef void (*rspamd_http_error_handler_t) (struct rspamd_http_connection *conn,
  83. GError *err);
  84. typedef int (*rspamd_http_finish_handler_t) (struct rspamd_http_connection *conn,
  85. struct rspamd_http_message *msg);
  86. typedef int (*rspamd_http_router_handler_t) (struct rspamd_http_connection_entry
  87. *conn_ent,
  88. struct rspamd_http_message *msg);
  89. typedef void (*rspamd_http_router_error_handler_t) (struct
  90. rspamd_http_connection_entry *conn_ent,
  91. GError *err);
  92. typedef void (*rspamd_http_router_finish_handler_t) (struct
  93. rspamd_http_connection_entry *conn_ent);
  94. /**
  95. * HTTP connection structure
  96. */
  97. struct rspamd_http_connection {
  98. struct rspamd_http_connection_private *priv;
  99. rspamd_http_body_handler_t body_handler;
  100. rspamd_http_error_handler_t error_handler;
  101. rspamd_http_finish_handler_t finish_handler;
  102. struct rspamd_keypair_cache *cache;
  103. gpointer ud;
  104. gsize max_size;
  105. unsigned opts;
  106. enum rspamd_http_connection_type type;
  107. gboolean finished;
  108. gint fd;
  109. gint ref;
  110. };
  111. struct rspamd_http_connection_entry {
  112. struct rspamd_http_connection_router *rt;
  113. struct rspamd_http_connection *conn;
  114. gpointer ud;
  115. gboolean is_reply;
  116. gboolean support_gzip;
  117. struct rspamd_http_connection_entry *prev, *next;
  118. };
  119. struct rspamd_http_connection_router {
  120. struct rspamd_http_connection_entry *conns;
  121. GHashTable *paths;
  122. GHashTable *response_headers;
  123. GPtrArray *regexps;
  124. struct timeval tv;
  125. struct timeval *ptv;
  126. struct event_base *ev_base;
  127. struct rspamd_keypair_cache *cache;
  128. gchar *default_fs_path;
  129. rspamd_http_router_handler_t unknown_method_handler;
  130. struct rspamd_cryptobox_keypair *key;
  131. rspamd_http_router_error_handler_t error_handler;
  132. rspamd_http_router_finish_handler_t finish_handler;
  133. };
  134. /**
  135. * Create new http connection
  136. * @param handler_t handler_t for body
  137. * @param opts options
  138. * @return new connection structure
  139. */
  140. struct rspamd_http_connection *rspamd_http_connection_new (
  141. rspamd_http_body_handler_t body_handler,
  142. rspamd_http_error_handler_t error_handler,
  143. rspamd_http_finish_handler_t finish_handler,
  144. unsigned opts,
  145. enum rspamd_http_connection_type type,
  146. struct rspamd_keypair_cache *cache,
  147. gpointer ssl_ctx);
  148. /**
  149. * Set key pointed by an opaque pointer
  150. * @param conn connection structure
  151. * @param key opaque key structure
  152. */
  153. void rspamd_http_connection_set_key (struct rspamd_http_connection *conn,
  154. struct rspamd_cryptobox_keypair *key);
  155. /**
  156. * Get peer's public key
  157. * @param conn connection structure
  158. * @return pubkey structure or NULL
  159. */
  160. const struct rspamd_cryptobox_pubkey* rspamd_http_connection_get_peer_key (
  161. struct rspamd_http_connection *conn);
  162. /**
  163. * Returns TRUE if a connection is encrypted
  164. * @param conn
  165. * @return
  166. */
  167. gboolean rspamd_http_connection_is_encrypted (struct rspamd_http_connection *conn);
  168. /**
  169. * Handle a request using socket fd and user data ud
  170. * @param conn connection structure
  171. * @param ud opaque user data
  172. * @param fd fd to read/write
  173. */
  174. void rspamd_http_connection_read_message (
  175. struct rspamd_http_connection *conn,
  176. gpointer ud,
  177. gint fd,
  178. struct timeval *timeout,
  179. struct event_base *base);
  180. void rspamd_http_connection_read_message_shared (
  181. struct rspamd_http_connection *conn,
  182. gpointer ud,
  183. gint fd,
  184. struct timeval *timeout,
  185. struct event_base *base);
  186. /**
  187. * Send reply using initialised connection
  188. * @param conn connection structure
  189. * @param msg HTTP message
  190. * @param ud opaque user data
  191. * @param fd fd to read/write
  192. */
  193. void rspamd_http_connection_write_message (
  194. struct rspamd_http_connection *conn,
  195. struct rspamd_http_message *msg,
  196. const gchar *host,
  197. const gchar *mime_type,
  198. gpointer ud,
  199. gint fd,
  200. struct timeval *timeout,
  201. struct event_base *base);
  202. void rspamd_http_connection_write_message_shared (
  203. struct rspamd_http_connection *conn,
  204. struct rspamd_http_message *msg,
  205. const gchar *host,
  206. const gchar *mime_type,
  207. gpointer ud,
  208. gint fd,
  209. struct timeval *timeout,
  210. struct event_base *base);
  211. /**
  212. * Free connection structure
  213. * @param conn
  214. */
  215. void rspamd_http_connection_free (struct rspamd_http_connection *conn);
  216. /**
  217. * Increase refcount for a connection
  218. * @param conn
  219. * @return
  220. */
  221. static inline struct rspamd_http_connection *
  222. rspamd_http_connection_ref (struct rspamd_http_connection *conn)
  223. {
  224. conn->ref++;
  225. return conn;
  226. }
  227. /**
  228. * Decrease a refcount for a connection and free it if refcount is equal to zero
  229. * @param conn
  230. */
  231. static void
  232. rspamd_http_connection_unref (struct rspamd_http_connection *conn)
  233. {
  234. if (--conn->ref <= 0) {
  235. rspamd_http_connection_free (conn);
  236. }
  237. }
  238. /**
  239. * Reset connection for a new request
  240. * @param conn
  241. */
  242. void rspamd_http_connection_reset (struct rspamd_http_connection *conn);
  243. /**
  244. * Extract the current message from a connection to deal with separately
  245. * @param conn
  246. * @return
  247. */
  248. struct rspamd_http_message * rspamd_http_connection_steal_msg (
  249. struct rspamd_http_connection *conn);
  250. /**
  251. * Copy the current message from a connection to deal with separately
  252. * @param conn
  253. * @return
  254. */
  255. struct rspamd_http_message * rspamd_http_connection_copy_msg (
  256. struct rspamd_http_message *msg, GError **err);
  257. /**
  258. * Create new HTTP message
  259. * @param type request or response
  260. * @return new http message
  261. */
  262. struct rspamd_http_message * rspamd_http_new_message (enum http_parser_type type);
  263. /**
  264. * Increase refcount number for an HTTP message
  265. * @param msg message to use
  266. * @return
  267. */
  268. struct rspamd_http_message * rspamd_http_message_ref (struct rspamd_http_message *msg);
  269. /**
  270. * Decrease number of refcounts for http message
  271. * @param msg
  272. */
  273. void rspamd_http_message_unref (struct rspamd_http_message *msg);
  274. /**
  275. * Sets a key for peer
  276. * @param msg
  277. * @param pk
  278. */
  279. void rspamd_http_message_set_peer_key (struct rspamd_http_message *msg,
  280. struct rspamd_cryptobox_pubkey *pk);
  281. /**
  282. * Create HTTP message from URL
  283. * @param url
  284. * @return new message or NULL
  285. */
  286. struct rspamd_http_message* rspamd_http_message_from_url (const gchar *url);
  287. /**
  288. * Returns body for a message
  289. * @param msg
  290. * @param blen pointer where to save body length
  291. * @return pointer to body start
  292. */
  293. const gchar *rspamd_http_message_get_body (struct rspamd_http_message *msg,
  294. gsize *blen);
  295. /**
  296. * Set message's body from the string
  297. * @param msg
  298. * @param data
  299. * @param len
  300. * @return TRUE if a message's body has been set
  301. */
  302. gboolean rspamd_http_message_set_body (struct rspamd_http_message *msg,
  303. const gchar *data, gsize len);
  304. /**
  305. * Set message's method by name
  306. * @param msg
  307. * @param method
  308. */
  309. void rspamd_http_message_set_method (struct rspamd_http_message *msg,
  310. const gchar *method);
  311. /**
  312. * Maps fd as message's body
  313. * @param msg
  314. * @param fd
  315. * @return TRUE if a message's body has been set
  316. */
  317. gboolean rspamd_http_message_set_body_from_fd (struct rspamd_http_message *msg,
  318. gint fd);
  319. /**
  320. * Uses rspamd_fstring_t as message's body, string is consumed by this operation
  321. * @param msg
  322. * @param fstr
  323. * @return TRUE if a message's body has been set
  324. */
  325. gboolean rspamd_http_message_set_body_from_fstring_steal (struct rspamd_http_message *msg,
  326. rspamd_fstring_t *fstr);
  327. /**
  328. * Uses rspamd_fstring_t as message's body, string is copied by this operation
  329. * @param msg
  330. * @param fstr
  331. * @return TRUE if a message's body has been set
  332. */
  333. gboolean rspamd_http_message_set_body_from_fstring_copy (struct rspamd_http_message *msg,
  334. const rspamd_fstring_t *fstr);
  335. /**
  336. * Appends data to message's body
  337. * @param msg
  338. * @param data
  339. * @param len
  340. * @return TRUE if a message's body has been set
  341. */
  342. gboolean rspamd_http_message_append_body (struct rspamd_http_message *msg,
  343. const gchar *data, gsize len);
  344. /**
  345. * Append a header to http message
  346. * @param rep
  347. * @param name
  348. * @param value
  349. */
  350. void rspamd_http_message_add_header (struct rspamd_http_message *msg,
  351. const gchar *name,
  352. const gchar *value);
  353. void rspamd_http_message_add_header_len (struct rspamd_http_message *msg,
  354. const gchar *name,
  355. const gchar *value,
  356. gsize len);
  357. void rspamd_http_message_add_header_fstr (struct rspamd_http_message *msg,
  358. const gchar *name,
  359. rspamd_fstring_t *value);
  360. /**
  361. * Search for a specified header in message
  362. * @param msg message
  363. * @param name name of header
  364. */
  365. const rspamd_ftok_t * rspamd_http_message_find_header (
  366. struct rspamd_http_message *msg,
  367. const gchar *name);
  368. /**
  369. * Search for a header that has multiple values
  370. * @param msg
  371. * @param name
  372. * @return list of rspamd_ftok_t * with values
  373. */
  374. GPtrArray* rspamd_http_message_find_header_multiple (
  375. struct rspamd_http_message *msg,
  376. const gchar *name);
  377. /**
  378. * Remove specific header from a message
  379. * @param msg
  380. * @param name
  381. * @return
  382. */
  383. gboolean rspamd_http_message_remove_header (struct rspamd_http_message *msg,
  384. const gchar *name);
  385. /**
  386. * Free HTTP message
  387. * @param msg
  388. */
  389. void rspamd_http_message_free (struct rspamd_http_message *msg);
  390. /**
  391. * Sets global maximum size for HTTP message being processed
  392. * @param sz
  393. */
  394. void rspamd_http_connection_set_max_size (struct rspamd_http_connection *conn,
  395. gsize sz);
  396. void rspamd_http_connection_disable_encryption (struct rspamd_http_connection *conn);
  397. /**
  398. * Increase refcount for shared file (if any) to prevent early memory unlinking
  399. * @param msg
  400. */
  401. struct rspamd_storage_shmem* rspamd_http_message_shmem_ref (struct rspamd_http_message *msg);
  402. /**
  403. * Decrease external ref for shmem segment associated with a message
  404. * @param msg
  405. */
  406. void rspamd_http_message_shmem_unref (struct rspamd_storage_shmem *p);
  407. /**
  408. * Returns message's flags
  409. * @param msg
  410. * @return
  411. */
  412. guint rspamd_http_message_get_flags (struct rspamd_http_message *msg);
  413. /**
  414. * Parse HTTP date header and return it as time_t
  415. * @param header HTTP date header
  416. * @param len length of header
  417. * @return time_t or (time_t)-1 in case of error
  418. */
  419. time_t rspamd_http_parse_date (const gchar *header, gsize len);
  420. /**
  421. * Create new http connection router and the associated HTTP connection
  422. * @param eh error handler callback
  423. * @param fh finish handler callback
  424. * @param default_fs_path if not NULL try to serve static files from
  425. * the specified directory
  426. * @return
  427. */
  428. struct rspamd_http_connection_router * rspamd_http_router_new (
  429. rspamd_http_router_error_handler_t eh,
  430. rspamd_http_router_finish_handler_t fh,
  431. struct timeval *timeout,
  432. struct event_base *base,
  433. const char *default_fs_path,
  434. struct rspamd_keypair_cache *cache);
  435. /**
  436. * Set encryption key for the HTTP router
  437. * @param router router structure
  438. * @param key opaque key structure
  439. */
  440. void rspamd_http_router_set_key (struct rspamd_http_connection_router *router,
  441. struct rspamd_cryptobox_keypair *key);
  442. /**
  443. * Add new path to the router
  444. */
  445. void rspamd_http_router_add_path (struct rspamd_http_connection_router *router,
  446. const gchar *path, rspamd_http_router_handler_t handler);
  447. /**
  448. * Add custom header to append to router replies
  449. * @param router
  450. * @param name
  451. * @param value
  452. */
  453. void rspamd_http_router_add_header (struct rspamd_http_connection_router *router,
  454. const gchar *name, const gchar *value);
  455. /**
  456. * Sets method to handle unknown request methods
  457. * @param router
  458. * @param handler
  459. */
  460. void rspamd_http_router_set_unknown_handler (struct rspamd_http_connection_router *router,
  461. rspamd_http_router_handler_t handler);
  462. /**
  463. * Inserts router headers to the outbound message
  464. * @param router
  465. * @param msg
  466. */
  467. void rspamd_http_router_insert_headers (struct rspamd_http_connection_router *router,
  468. struct rspamd_http_message *msg);
  469. struct rspamd_regexp_s;
  470. /**
  471. * Adds new pattern to router, regexp object is refcounted by this function
  472. * @param router
  473. * @param re
  474. * @param handler
  475. */
  476. void rspamd_http_router_add_regexp (struct rspamd_http_connection_router *router,
  477. struct rspamd_regexp_s *re, rspamd_http_router_handler_t handler);
  478. /**
  479. * Handle new accepted socket
  480. * @param router router object
  481. * @param fd server socket
  482. * @param ud opaque userdata
  483. */
  484. void rspamd_http_router_handle_socket (
  485. struct rspamd_http_connection_router *router,
  486. gint fd,
  487. gpointer ud);
  488. /**
  489. * Free router and all connections associated
  490. * @param router
  491. */
  492. void rspamd_http_router_free (struct rspamd_http_connection_router *router);
  493. /**
  494. * Extract arguments from a message's URI contained inside query string decoding
  495. * them if needed
  496. * @param msg HTTP request message
  497. * @return new GHashTable which maps rspamd_ftok_t* to rspamd_ftok_t*
  498. * (table must be freed by a caller)
  499. */
  500. GHashTable* rspamd_http_message_parse_query (struct rspamd_http_message *msg);
  501. /**
  502. * Prints HTTP date from `time` to `buf` using standard HTTP date format
  503. * @param buf date buffer
  504. * @param len length of buffer
  505. * @param time time in unix seconds
  506. * @return number of bytes written
  507. */
  508. glong rspamd_http_date_format (gchar *buf, gsize len, time_t time);
  509. /**
  510. * Normalize HTTP path removing dot sequences and repeating '/' symbols as
  511. * per rfc3986#section-5.2
  512. * @param path
  513. * @param len
  514. * @param nlen
  515. */
  516. void rspamd_http_normalize_path_inplace (gchar *path, guint len, guint *nlen);
  517. #endif /* HTTP_H_ */