make protocols const require explicit context API BREAK
[platform/upstream/libwebsockets.git] / lib / extension.c
1 #include "private-libwebsockets.h"
2
3 #include "extension-deflate-frame.h"
4 #include "extension-deflate-stream.h"
5
6 struct lws_extension lws_internal_extensions[] = {
7 #ifdef LWS_EXT_DEFLATE_STREAM
8         {
9                 "deflate-stream",
10                 lws_extension_callback_deflate_stream,
11                 sizeof(struct lws_ext_deflate_stream_conn)
12         },
13 #else
14         {
15                 "x-webkit-deflate-frame",
16                 lws_extension_callback_deflate_frame,
17                 sizeof(struct lws_ext_deflate_frame_conn)
18         },
19         {
20                 "deflate-frame",
21                 lws_extension_callback_deflate_frame,
22                 sizeof(struct lws_ext_deflate_frame_conn)
23         },
24 #endif
25         { /* terminator */
26                 NULL, NULL, 0
27         }
28 };
29
30 LWS_VISIBLE void
31 lws_context_init_extensions(struct lws_context_creation_info *info,
32                                     struct lws_context *context)
33 {
34         context->extensions = info->extensions;
35         lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
36 }
37
38 LWS_VISIBLE struct lws_extension *lws_get_internal_extensions()
39 {
40         return lws_internal_extensions;
41 }
42
43
44 /* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */
45
46 int lws_ext_callback_for_each_active(struct lws *wsi, int reason,
47                                 void *arg, int len)
48 {
49         int n, m, handled = 0;
50
51         for (n = 0; n < wsi->count_active_extensions; n++) {
52                 m = wsi->active_extensions[n]->callback(
53                         lws_get_ctx(wsi),
54                         wsi->active_extensions[n], wsi,
55                         reason,
56                         wsi->active_extensions_user[n],
57                         arg, len);
58                 if (m < 0) {
59                         lwsl_ext(
60                          "Extension '%s' failed to handle callback %d!\n",
61                                       wsi->active_extensions[n]->name, reason);
62                         return -1;
63                 }
64                 if (m > handled)
65                         handled = m;
66         }
67         
68         return handled;
69 }
70
71 int lws_ext_callback_for_each_extension_type(
72                 struct lws_context *context, struct lws *wsi,
73                                 int reason, void *arg, int len)
74 {
75         int n = 0, m, handled = 0;
76         const struct lws_extension *ext = context->extensions;
77
78         while (ext && ext->callback && !handled) {
79                 m = ext->callback(context, ext, wsi, reason,
80                                                 (void *)(long)n, arg, len);
81                 if (m < 0) {
82                         lwsl_ext(
83                          "Extension '%s' failed to handle callback %d!\n",
84                                       wsi->active_extensions[n]->name, reason);
85                         return -1;
86                 }
87                 if (m)
88                         handled = 1;
89
90                 ext++;
91                 n++;
92         }
93         
94         return 0;
95 }
96
97 int
98 lws_issue_raw_ext_access(struct lws *wsi,
99                                                  unsigned char *buf, size_t len)
100 {
101         int ret;
102         struct lws_tokens eff_buf;
103         int m;
104         int n = 0;
105
106         eff_buf.token = (char *)buf;
107         eff_buf.token_len = len;
108
109         /*
110          * while we have original buf to spill ourselves, or extensions report
111          * more in their pipeline
112          */
113
114         ret = 1;
115         while (ret == 1) {
116
117                 /* default to nobody has more to spill */
118
119                 ret = 0;
120
121                 /* show every extension the new incoming data */
122                 m = lws_ext_callback_for_each_active(wsi,
123                                LWS_EXT_CALLBACK_PACKET_TX_PRESEND, &eff_buf, 0);
124                 if (m < 0)
125                         return -1;
126                 if (m) /* handled */
127                         ret = 1;
128
129                 if ((char *)buf != eff_buf.token)
130                         /*
131                          * extension recreated it:
132                          * need to buffer this if not all sent
133                          */
134                         wsi->u.ws.clean_buffer = 0;
135
136                 /* assuming they left us something to send, send it */
137
138                 if (eff_buf.token_len) {
139                         n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
140                                                             eff_buf.token_len);
141                         if (n < 0) {
142                                 lwsl_info("closing from ext access\n");
143                                 return -1;
144                         }
145
146                         /* always either sent it all or privately buffered */
147                         if (wsi->u.ws.clean_buffer)
148                                 len = n;
149                 }
150
151                 lwsl_parser("written %d bytes to client\n", n);
152
153                 /* no extension has more to spill?  Then we can go */
154
155                 if (!ret)
156                         break;
157
158                 /* we used up what we had */
159
160                 eff_buf.token = NULL;
161                 eff_buf.token_len = 0;
162
163                 /*
164                  * Did that leave the pipe choked?
165                  * Or we had to hold on to some of it?
166                  */
167
168                 if (!lws_send_pipe_choked(wsi) && !wsi->truncated_send_len)
169                         /* no we could add more, lets's do that */
170                         continue;
171
172                 lwsl_debug("choked\n");
173
174                 /*
175                  * Yes, he's choked.  Don't spill the rest now get a callback
176                  * when he is ready to send and take care of it there
177                  */
178                 lws_callback_on_writable(
179                                              lws_get_ctx(wsi), wsi);
180                 wsi->extension_data_pending = 1;
181                 ret = 0;
182         }
183
184         return len;
185 }
186
187 int
188 lws_any_extension_handled(struct lws_context *context,
189                           struct lws *wsi,
190                           enum lws_extension_callback_reasons r,
191                                                        void *v, size_t len)
192 {
193         int n;
194         int handled = 0;
195
196         /* maybe an extension will take care of it for us */
197
198         for (n = 0; n < wsi->count_active_extensions && !handled; n++) {
199                 if (!wsi->active_extensions[n]->callback)
200                         continue;
201
202                 handled |= wsi->active_extensions[n]->callback(context,
203                         wsi->active_extensions[n], wsi,
204                         r, wsi->active_extensions_user[n], v, len);
205         }
206
207         return handled;
208 }