1 /*
2  *  Copyright (C) 2004-2008 Christos Tsantilas
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA  02110-1301  USA.
18  */
19 
20 /**
21  \defgroup ICAPCLIENT ICAP client request API
22  \ingroup API
23  * API for implementing ICAP clients
24  */
25 
26 #ifndef _REQUEST_H
27 #define _REQUEST_H
28 
29 #include "header.h"
30 #include "service.h"
31 #include "net_io.h"
32 #include "array.h"
33 
34 #ifdef __cplusplus
35 extern "C"
36 {
37 #endif
38 
39 /**
40  \defgroup REQUEST ICAP request API
41  \ingroup API
42  * ICAP request related API.
43  */
44 
45 /**
46  \defgroup ICAPCLIENT ICAP client request API
47  \ingroup API
48  * API for implementing ICAP clients
49  */
50 
51 //enum REQUEST_STATUS { WAIT,SERVED };
52 
53 enum GETDATA_STATUS {GET_NOTHING = 0,GET_HEADERS,GET_PREVIEW,GET_BODY,GET_EOF};
54 enum SENDDATA_STATUS {SEND_NOTHING = 0, SEND_RESPHEAD, SEND_HEAD1, SEND_HEAD2, SEND_HEAD3, SEND_BODY, SEND_EOF };
55 
56 /*enum BODY_RESPONCE_STATUS{ CHUNK_DEF = 1,CHUNK_BODY,CHUNK_END};*/
57 
58 enum CLIENT_STATUS {
59     CLIENT_INIT = 0,
60     CLIENT_SEND_HEADERS,
61     CLIENT_SEND_HEADERS_WRITE_NOTHING = CLIENT_SEND_HEADERS,
62     CLIENT_SEND_HEADERS_WRITE_ICAP_HEADERS,
63     CLIENT_SEND_HEADERS_WRITE_REQ_HEADERS,
64     CLIENT_SEND_HEADERS_WRITE_RES_HEADERS,
65     CLIENT_SEND_HEADERS_WRITE_PREVIEW_INFO,
66     CLIENT_SEND_HEADERS_WRITE_PREVIEW,
67     CLIENT_SEND_HEADERS_WRITE_EOF_INFO,
68     CLIENT_SEND_HEADERS_FINISHED,
69 
70     CLIENT_READ_PREVIEW_RESPONSE,
71 
72     CLIENT_PROCESS_DATA,
73     CLIENT_PROCESS_DATA_GET_NOTHING = CLIENT_PROCESS_DATA,
74     CLIENT_PROCESS_DATA_GET_HEADERS,
75     CLIENT_PROCESS_DATA_HEADERS_FINISHED,
76     CLIENT_PROCESS_DATA_GET_BODY,
77     CLIENT_PROCESS_DATA_GET_EOF
78 };
79 
80 #define NEEDS_TO_READ_FROM_ICAP  0x1
81 #define NEEDS_TO_WRITE_TO_ICAP   0x2
82 #define NEEDS_TO_READ_USER_DATA  0x4
83 #define NEEDS_TO_WRITE_USER_DATA 0x8
84 
85 
86 #define CI_NO_STATUS   0
87 #define CI_OK                1
88 #define CI_NEEDS_MORE 2
89 #define CI_ERROR          -1
90 #define CI_EOF              -2
91 
92 
93 #define EXTRA_CHUNK_SIZE  30
94 #define MAX_CHUNK_SIZE    4064   /*4096 -EXTRA_CHUNK_SIZE-2*/
95 #define MAX_USERNAME_LEN 255
96 
97 typedef struct ci_buf {
98     char *buf;
99     int size;
100     int used;
101 } ci_buf_t;
102 
103 
104 struct ci_service_module;
105 struct ci_ring_buf;
106 
107 /**
108    \typedef ci_request_t
109    \ingroup REQUEST
110    * This is the struct which holds all the data which represent an ICAP
111    * request. The developers should not access directly the fields of
112    * this struct but better use the documented macros and functions
113 */
114 typedef struct ci_request {
115     ci_connection_t *connection;
116     int packed;
117     int type;
118     char req_server[CI_MAXHOSTNAMELEN+1];
119     int access_type;
120     char user[MAX_USERNAME_LEN+1];
121     char service[MAX_SERVICE_NAME+1];
122     char args[MAX_SERVICE_ARGS + 1];
123     int preview;
124     int keepalive;
125     int allow204;
126     int hasbody;
127     int responce_hasbody;
128     struct ci_buf preview_data;
129     struct ci_service_module *current_service_mod;
130     ci_headers_list_t *request_header;
131     ci_headers_list_t *response_header;
132     ci_encaps_entity_t *entities[5];//At most 3 and 1 for termination.....
133     ci_encaps_entity_t *trash_entities[7];
134     ci_headers_list_t *xheaders;
135 
136     void *service_data;
137 
138     char rbuf[BUFSIZE];
139     char wbuf[MAX_CHUNK_SIZE+EXTRA_CHUNK_SIZE+2];
140     int eof_received;
141     int eof_sent;
142     int data_locked;
143 
144     char *pstrblock_read;
145     int  pstrblock_read_len;
146     unsigned int current_chunk_len;
147     unsigned int chunk_bytes_read;
148     unsigned int write_to_module_pending;
149 
150     int status;
151     int return_code;
152     char *pstrblock_responce;
153     int remain_send_block_bytes;
154 
155     /*Used to echo data back to a client which does not support preview
156       in the case of 204 outside preview.*/
157     struct ci_ring_buf *echo_body;
158 
159     /*Caching values for various subsystems*/
160     int preview_data_type;
161     int auth_required;
162 
163     /*log string*/
164     char *log_str;
165     ci_str_array_t *attributes;
166 
167     /* statistics */
168     uint64_t bytes_in; /*May include bytes from next pipelined request*/
169     uint64_t bytes_out;
170     uint64_t request_bytes_in; /*Current request input bytes*/
171     uint64_t http_bytes_in;
172     uint64_t http_bytes_out;
173     uint64_t body_bytes_in;
174     uint64_t body_bytes_out;
175 
176     /* added flags/variables*/
177     int allow206;
178     int64_t i206_use_original_body;
179     ci_ip_t xclient_ip;
180 } ci_request_t;
181 
182 #define lock_data(req) (req->data_locked = 1)
183 #define unlock_data(req) (req->data_locked = 0)
184 
185 /*This functions needed in server (mpmt_server.c ) */
186 ci_request_t *newrequest(ci_connection_t *connection);
187 int recycle_request(ci_request_t *req,ci_connection_t *connection);
188 int keepalive_request(ci_request_t *req);
189 int process_request(ci_request_t *);
190 
191 /*Functions used in both server and icap-client library*/
192 CI_DECLARE_FUNC(int) parse_chunk_data(ci_request_t *req, char **wdata);
193 CI_DECLARE_FUNC(int) net_data_read(ci_request_t *req);
194 CI_DECLARE_FUNC(int) process_encapsulated(ci_request_t *req, const char *buf);
195 
196 /*********************************************/
197 /*Buffer functions (I do not know if they must included in ci library....) */
198 CI_DECLARE_FUNC(void)  ci_buf_init(struct ci_buf *buf);
199 CI_DECLARE_FUNC(void)  ci_buf_reset(struct ci_buf *buf);
200 CI_DECLARE_FUNC(int)   ci_buf_mem_alloc(struct ci_buf *buf,int size);
201 CI_DECLARE_FUNC(void)  ci_buf_mem_free(struct ci_buf *buf);
202 CI_DECLARE_FUNC(int)   ci_buf_write(struct ci_buf *buf,char *data,int len);
203 CI_DECLARE_FUNC(int)   ci_buf_reset_size(struct ci_buf *buf,int req_size);
204 
205 /***************/
206 /*API defines */
207 #define ci_service_data(req) ((req)->service_data)
208 #define ci_allow204(req)     ((req)->allow204)
209 #define ci_allow206(req)     ((req)->allow206)
210 /*API functions ......*/
211 CI_DECLARE_FUNC(ci_request_t *)  ci_request_alloc(ci_connection_t *connection);
212 CI_DECLARE_FUNC(void)         ci_request_reset(ci_request_t *req);
213 CI_DECLARE_FUNC(void)         ci_request_destroy(ci_request_t *req);
214 CI_DECLARE_FUNC(void)         ci_request_pack(ci_request_t *req);
215 CI_DECLARE_FUNC(void)         ci_response_pack(ci_request_t *req);
216 CI_DECLARE_FUNC(ci_encaps_entity_t *) ci_request_alloc_entity(ci_request_t *req,int type,int val);
217 CI_DECLARE_FUNC(int)          ci_request_release_entity(ci_request_t *req,int pos);
218 CI_DECLARE_FUNC(char *)       ci_request_set_log_str(ci_request_t *req, char *logstr);
219 CI_DECLARE_FUNC(int)       ci_request_set_str_attribute(ci_request_t *req, const char *name, const char *value);
220 
221 CI_DECLARE_FUNC(int)          ci_request_206_origin_body(ci_request_t *req, uint64_t offset);
222 
223 /*ICAP client api*/
224 CI_DECLARE_FUNC(ci_request_t *)  ci_client_request(ci_connection_t *conn,const char *server,const char *service);
225 CI_DECLARE_FUNC(void)         ci_client_request_reuse(ci_request_t *req);
226 
227 CI_DECLARE_FUNC(int)          ci_client_get_server_options(ci_request_t *req,int timeout);
228 CI_DECLARE_FUNC(int)          ci_client_get_server_options_nonblocking(ci_request_t *req);
229 
230 CI_DECLARE_FUNC(int)          ci_client_icapfilter(ci_request_t *req,
231         int timeout,
232         ci_headers_list_t *req_headers,
233         ci_headers_list_t *resp_headers,
234         void *data_source,
235         int (*source_read)(void *,char *,int),
236         void *data_dest,
237         int (*dest_write) (void *,char *,int));
238 
239 /**
240  \ingroup ICAPCLIENT
241  * Function to send HTTP objects to an ICAP server for processing. It sends
242  * the HTTP request headers, and the HTTP response from HTTP server (headers
243  * plus body data), and receives modified HTTP response headers and body data.
244  \param req The ci_request_t object.
245  \param io_action is a combination set of ci_wait_for_read and
246  *      ci_wait_for_write flags. It has the meaning that the
247  *      ci_client_icapfilter_nonblocking can read from or write to ICAP server.
248  \param req_headers The HTTP request headers to use.
249  \param resp_headers The HTTP response headers to use.
250  \param data_source User data to use with source_read callback function.
251  \param source_read Callback function to use for reading HTTP object body data.
252  \param data_dest User data to use with dest_write callback function.
253  \param dest_write Callback function to use for storing modified body data.
254  \return combination of the following flags: NEEDS_TO_READ_FROM_ICAP,
255  *       NEEDS_TO_WRITE_TO_ICAP, NEEDS_TO_READ_USER_DATA and
256  *       NEEDS_TO_WRITE_USER_DATA.
257  */
258 CI_DECLARE_FUNC(int) ci_client_icapfilter_nonblocking(ci_request_t * req, int io_action,
259         ci_headers_list_t * req_headers,
260         ci_headers_list_t * resp_headers,
261         void *data_source,
262         int (*source_read) (void *, char *, int),
263         void *data_dest,
264         int (*dest_write) (void *, char *, int));
265 
266 CI_DECLARE_FUNC(int) ci_client_http_headers_completed(ci_request_t * req);
267 
268 CI_DECLARE_FUNC(void) ci_client_set_user_agent(const char *agent);
269 
270 CI_DECLARE_FUNC(void) ci_client_library_init();
271 
272 CI_DECLARE_FUNC(void) ci_client_library_release();
273 
274 /** Deprecated. Use ci_connect_to declared in net_io.h instead. */
275 CI_DECLARE_FUNC(ci_connection_t *)  ci_client_connect_to(char *servername,int port,int proto);
276 
277 #ifdef __CI_COMPAT
278 #define request_t   ci_request_t
279 #endif
280 
281 #ifdef __cplusplus
282 }
283 #endif
284 
285 #endif
286