2 * uhttpd - Tiny single-threaded httpd - ubus handler
4 * Copyright (C) 2012 Jo-Philipp Wich <xm@subsignal.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include "uhttpd-utils.h"
21 #include "uhttpd-ubus.h"
29 static const struct blobmsg_policy new_policy
[__UH_UBUS_SN_MAX
] = {
30 [UH_UBUS_SN_TIMEOUT
] = { .name
= "timeout", .type
= BLOBMSG_TYPE_INT32
},
39 static const struct blobmsg_policy sid_policy
[__UH_UBUS_SI_MAX
] = {
40 [UH_UBUS_SI_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
50 static const struct blobmsg_policy set_policy
[__UH_UBUS_SS_MAX
] = {
51 [UH_UBUS_SS_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
52 [UH_UBUS_SS_VALUES
] = { .name
= "values", .type
= BLOBMSG_TYPE_TABLE
},
62 static const struct blobmsg_policy get_policy
[__UH_UBUS_SG_MAX
] = {
63 [UH_UBUS_SG_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
64 [UH_UBUS_SG_KEYS
] = { .name
= "keys", .type
= BLOBMSG_TYPE_ARRAY
},
74 static const struct blobmsg_policy acl_policy
[__UH_UBUS_SA_MAX
] = {
75 [UH_UBUS_SA_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
76 [UH_UBUS_SA_OBJECTS
] = { .name
= "objects", .type
= BLOBMSG_TYPE_ARRAY
},
81 uh_ubus_strmatch(const char *str
, const char *pat
)
95 if (uh_ubus_strmatch(str
, pat
+1))
98 if (*str
&& uh_ubus_strmatch(str
+1, pat
))
103 else if (*str
++ != *pat
++)
109 return (!*str
&& !*pat
);
113 uh_ubus_avlcmp(const void *k1
, const void *k2
, void *ptr
)
115 return strcmp((char *)k1
, (char *)k2
);
119 uh_ubus_random(char *dest
)
122 unsigned char buf
[16] = { 0 };
125 if ((f
= fopen("/dev/urandom", "r")) != NULL
)
127 fread(buf
, 1, sizeof(buf
), f
);
131 for (i
= 0; i
< sizeof(buf
); i
++)
132 sprintf(dest
+ (i
<<1), "%02x", buf
[i
]);
136 uh_ubus_session_dump_data(struct uh_ubus_session
*ses
, struct blob_buf
*b
)
138 struct uh_ubus_session_data
*d
;
140 avl_for_each_element(&ses
->data
, d
, avl
)
142 blobmsg_add_field(b
, blobmsg_type(d
->attr
), blobmsg_name(d
->attr
),
143 blobmsg_data(d
->attr
), blobmsg_data_len(d
->attr
));
148 uh_ubus_session_dump_acls(struct uh_ubus_session
*ses
, struct blob_buf
*b
)
150 struct uh_ubus_session_acl
*acl
;
151 const char *lastobj
= NULL
;
154 avl_for_each_element(&ses
->acls
, acl
, avl
)
156 if (!lastobj
|| strcmp(acl
->object
, lastobj
))
158 if (c
) blobmsg_close_array(b
, c
);
159 c
= blobmsg_open_array(b
, acl
->object
);
162 blobmsg_add_string(b
, NULL
, acl
->function
);
163 lastobj
= acl
->object
;
166 if (c
) blobmsg_close_array(b
, c
);
170 uh_ubus_session_dump(struct uh_ubus_session
*ses
,
171 struct ubus_context
*ctx
,
172 struct ubus_request_data
*req
)
177 memset(&b
, 0, sizeof(b
));
178 blob_buf_init(&b
, 0);
180 blobmsg_add_string(&b
, "sid", ses
->id
);
181 blobmsg_add_u32(&b
, "timeout", ses
->timeout
);
182 blobmsg_add_u32(&b
, "touched", ses
->touched
.tv_sec
);
184 c
= blobmsg_open_table(&b
, "acls");
185 uh_ubus_session_dump_acls(ses
, &b
);
186 blobmsg_close_table(&b
, c
);
188 c
= blobmsg_open_table(&b
, "data");
189 uh_ubus_session_dump_data(ses
, &b
);
190 blobmsg_close_table(&b
, c
);
192 ubus_send_reply(ctx
, req
, b
.head
);
196 static struct uh_ubus_session
*
197 uh_ubus_session_create(struct uh_ubus_state
*state
, int timeout
)
199 struct uh_ubus_session
*ses
;
201 ses
= malloc(sizeof(*ses
));
203 /* failed to allocate memory... */
207 memset(ses
, 0, sizeof(*ses
));
209 uh_ubus_random(ses
->id
);
211 ses
->timeout
= timeout
;
212 ses
->avl
.key
= ses
->id
;
214 avl_insert(&state
->sessions
, &ses
->avl
);
215 avl_init(&ses
->acls
, uh_ubus_avlcmp
, true, NULL
);
216 avl_init(&ses
->data
, uh_ubus_avlcmp
, false, NULL
);
217 clock_gettime(CLOCK_MONOTONIC
, &ses
->touched
);
223 static struct uh_ubus_session
*
224 uh_ubus_session_get(struct uh_ubus_state
*state
, const char *id
)
226 struct uh_ubus_session
*ses
;
228 ses
= avl_find_element(&state
->sessions
, id
, ses
, avl
);
231 clock_gettime(CLOCK_MONOTONIC
, &ses
->touched
);
237 uh_ubus_session_destroy(struct uh_ubus_state
*state
,
238 struct uh_ubus_session
*ses
)
240 struct uh_ubus_session_acl
*acl
, *nacl
;
241 struct uh_ubus_session_data
*data
, *ndata
;
243 avl_remove_all_elements(&ses
->acls
, acl
, avl
, nacl
)
246 avl_remove_all_elements(&ses
->data
, data
, avl
, ndata
)
249 avl_delete(&state
->sessions
, &ses
->avl
);
254 uh_ubus_session_cleanup(struct uh_ubus_state
*state
)
257 struct uh_ubus_session
*ses
, *nses
;
259 clock_gettime(CLOCK_MONOTONIC
, &now
);
261 avl_for_each_element_safe(&state
->sessions
, ses
, avl
, nses
)
263 if ((now
.tv_sec
- ses
->touched
.tv_sec
) >= ses
->timeout
)
264 uh_ubus_session_destroy(state
, ses
);
270 uh_ubus_handle_create(struct ubus_context
*ctx
, struct ubus_object
*obj
,
271 struct ubus_request_data
*req
, const char *method
,
272 struct blob_attr
*msg
)
274 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
275 struct uh_ubus_session
*ses
;
276 struct blob_attr
*tb
[__UH_UBUS_SN_MAX
];
278 int timeout
= state
->timeout
;
280 blobmsg_parse(new_policy
, __UH_UBUS_SN_MAX
, tb
, blob_data(msg
), blob_len(msg
));
282 /* TODO: make this a uloop timeout */
283 uh_ubus_session_cleanup(state
);
285 if (tb
[UH_UBUS_SN_TIMEOUT
])
286 timeout
= *(uint32_t *)blobmsg_data(tb
[UH_UBUS_SN_TIMEOUT
]);
288 ses
= uh_ubus_session_create(state
, timeout
);
291 uh_ubus_session_dump(ses
, ctx
, req
);
297 uh_ubus_handle_list(struct ubus_context
*ctx
, struct ubus_object
*obj
,
298 struct ubus_request_data
*req
, const char *method
,
299 struct blob_attr
*msg
)
301 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
302 struct uh_ubus_session
*ses
;
303 struct blob_attr
*tb
[__UH_UBUS_SI_MAX
];
305 blobmsg_parse(sid_policy
, __UH_UBUS_SI_MAX
, tb
, blob_data(msg
), blob_len(msg
));
307 /* TODO: make this a uloop timeout */
308 uh_ubus_session_cleanup(state
);
310 if (!tb
[UH_UBUS_SI_SID
])
312 avl_for_each_element(&state
->sessions
, ses
, avl
)
313 uh_ubus_session_dump(ses
, ctx
, req
);
317 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SI_SID
]));
320 return UBUS_STATUS_NOT_FOUND
;
322 uh_ubus_session_dump(ses
, ctx
, req
);
330 uh_ubus_session_grant(struct uh_ubus_session
*ses
, struct ubus_context
*ctx
,
331 const char *object
, const char *function
)
333 struct uh_ubus_session_acl
*acl
, *nacl
;
335 acl
= avl_find_element(&ses
->acls
, object
, acl
, avl
);
339 avl_for_element_to_last(&ses
->acls
, acl
, acl
, avl
)
341 if (!strcmp(acl
->function
, function
))
346 nacl
= malloc(sizeof(*nacl
) + strlen(object
) + strlen(function
) + 2);
350 memset(nacl
, 0, sizeof(*nacl
));
351 nacl
->function
= nacl
->object
+ 1;
352 nacl
->function
+= sprintf(nacl
->object
, "%s", object
);
353 sprintf(nacl
->function
, "%s", function
);
355 nacl
->avl
.key
= nacl
->object
;
356 avl_insert(&ses
->acls
, &nacl
->avl
);
363 uh_ubus_session_revoke(struct uh_ubus_session
*ses
, struct ubus_context
*ctx
,
364 const char *object
, const char *function
)
366 struct uh_ubus_session_acl
*acl
, *nacl
;
368 if (!object
&& !function
)
370 avl_remove_all_elements(&ses
->acls
, acl
, avl
, nacl
)
375 avl_for_each_element_safe(&ses
->acls
, acl
, avl
, nacl
)
377 if (uh_ubus_strmatch(acl
->object
, object
) &&
378 uh_ubus_strmatch(acl
->function
, function
))
380 avl_delete(&ses
->acls
, &acl
->avl
);
391 uh_ubus_handle_grant(struct ubus_context
*ctx
, struct ubus_object
*obj
,
392 struct ubus_request_data
*req
, const char *method
,
393 struct blob_attr
*msg
)
395 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
396 struct uh_ubus_session
*ses
;
397 struct blob_attr
*tb
[__UH_UBUS_SA_MAX
];
398 struct blob_attr
*attr
, *sattr
;
399 const char *object
, *function
;
402 blobmsg_parse(acl_policy
, __UH_UBUS_SA_MAX
, tb
, blob_data(msg
), blob_len(msg
));
404 if (!tb
[UH_UBUS_SA_SID
] || !tb
[UH_UBUS_SA_OBJECTS
])
405 return UBUS_STATUS_INVALID_ARGUMENT
;
407 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SA_SID
]));
410 return UBUS_STATUS_NOT_FOUND
;
412 blobmsg_for_each_attr(attr
, tb
[UH_UBUS_SA_OBJECTS
], rem1
)
414 if (blob_id(attr
) != BLOBMSG_TYPE_ARRAY
)
420 blobmsg_for_each_attr(sattr
, attr
, rem2
)
422 if (blob_id(sattr
) != BLOBMSG_TYPE_STRING
)
426 object
= blobmsg_data(sattr
);
428 function
= blobmsg_data(sattr
);
433 if (object
&& function
)
434 uh_ubus_session_grant(ses
, ctx
, object
, function
);
441 uh_ubus_handle_revoke(struct ubus_context
*ctx
, struct ubus_object
*obj
,
442 struct ubus_request_data
*req
, const char *method
,
443 struct blob_attr
*msg
)
445 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
446 struct uh_ubus_session
*ses
;
447 struct blob_attr
*tb
[__UH_UBUS_SA_MAX
];
448 struct blob_attr
*attr
, *sattr
;
449 const char *object
, *function
;
452 blobmsg_parse(acl_policy
, __UH_UBUS_SA_MAX
, tb
, blob_data(msg
), blob_len(msg
));
454 if (!tb
[UH_UBUS_SA_SID
])
455 return UBUS_STATUS_INVALID_ARGUMENT
;
457 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SA_SID
]));
460 return UBUS_STATUS_NOT_FOUND
;
462 if (!tb
[UH_UBUS_SA_OBJECTS
])
464 uh_ubus_session_revoke(ses
, ctx
, NULL
, NULL
);
468 blobmsg_for_each_attr(attr
, tb
[UH_UBUS_SA_OBJECTS
], rem1
)
470 if (blob_id(attr
) != BLOBMSG_TYPE_ARRAY
)
476 blobmsg_for_each_attr(sattr
, attr
, rem2
)
478 if (blob_id(sattr
) != BLOBMSG_TYPE_STRING
)
482 object
= blobmsg_data(sattr
);
484 function
= blobmsg_data(sattr
);
489 if (object
&& function
)
490 uh_ubus_session_revoke(ses
, ctx
, object
, function
);
498 uh_ubus_handle_set(struct ubus_context
*ctx
, struct ubus_object
*obj
,
499 struct ubus_request_data
*req
, const char *method
,
500 struct blob_attr
*msg
)
502 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
503 struct uh_ubus_session
*ses
;
504 struct uh_ubus_session_data
*data
;
505 struct blob_attr
*tb
[__UH_UBUS_SA_MAX
];
506 struct blob_attr
*attr
;
509 blobmsg_parse(set_policy
, __UH_UBUS_SS_MAX
, tb
, blob_data(msg
), blob_len(msg
));
511 if (!tb
[UH_UBUS_SS_SID
] || !tb
[UH_UBUS_SS_VALUES
])
512 return UBUS_STATUS_INVALID_ARGUMENT
;
514 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SS_SID
]));
517 return UBUS_STATUS_NOT_FOUND
;
519 blobmsg_for_each_attr(attr
, tb
[UH_UBUS_SS_VALUES
], rem
)
521 if (!blobmsg_name(attr
)[0])
524 data
= avl_find_element(&ses
->data
, blobmsg_name(attr
), data
, avl
);
528 avl_delete(&ses
->data
, &data
->avl
);
532 data
= malloc(sizeof(*data
) + blob_pad_len(attr
));
537 memset(data
, 0, sizeof(*data
) + blob_pad_len(attr
));
538 memcpy(data
->attr
, attr
, blob_pad_len(attr
));
540 data
->avl
.key
= blobmsg_name(data
->attr
);
541 avl_insert(&ses
->data
, &data
->avl
);
548 uh_ubus_handle_get(struct ubus_context
*ctx
, struct ubus_object
*obj
,
549 struct ubus_request_data
*req
, const char *method
,
550 struct blob_attr
*msg
)
552 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
553 struct uh_ubus_session
*ses
;
554 struct uh_ubus_session_data
*data
;
555 struct blob_attr
*tb
[__UH_UBUS_SA_MAX
];
556 struct blob_attr
*attr
;
561 blobmsg_parse(get_policy
, __UH_UBUS_SG_MAX
, tb
, blob_data(msg
), blob_len(msg
));
563 if (!tb
[UH_UBUS_SG_SID
])
564 return UBUS_STATUS_INVALID_ARGUMENT
;
566 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SG_SID
]));
569 return UBUS_STATUS_NOT_FOUND
;
571 memset(&b
, 0, sizeof(b
));
572 blob_buf_init(&b
, 0);
573 c
= blobmsg_open_table(&b
, "values");
575 if (!tb
[UH_UBUS_SG_KEYS
])
577 uh_ubus_session_dump_data(ses
, &b
);
581 blobmsg_for_each_attr(attr
, tb
[UH_UBUS_SG_KEYS
], rem
)
583 if (blob_id(attr
) != BLOBMSG_TYPE_STRING
)
586 data
= avl_find_element(&ses
->data
, blobmsg_data(attr
), data
, avl
);
591 blobmsg_add_field(&b
, blobmsg_type(data
->attr
),
592 blobmsg_name(data
->attr
),
593 blobmsg_data(data
->attr
),
594 blobmsg_data_len(data
->attr
));
598 blobmsg_close_table(&b
, c
);
599 ubus_send_reply(ctx
, req
, b
.head
);
606 uh_ubus_handle_unset(struct ubus_context
*ctx
, struct ubus_object
*obj
,
607 struct ubus_request_data
*req
, const char *method
,
608 struct blob_attr
*msg
)
610 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
611 struct uh_ubus_session
*ses
;
612 struct uh_ubus_session_data
*data
, *ndata
;
613 struct blob_attr
*tb
[__UH_UBUS_SA_MAX
];
614 struct blob_attr
*attr
;
617 blobmsg_parse(get_policy
, __UH_UBUS_SG_MAX
, tb
, blob_data(msg
), blob_len(msg
));
619 if (!tb
[UH_UBUS_SG_SID
])
620 return UBUS_STATUS_INVALID_ARGUMENT
;
622 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SG_SID
]));
625 return UBUS_STATUS_NOT_FOUND
;
627 if (!tb
[UH_UBUS_SG_KEYS
])
629 avl_remove_all_elements(&ses
->data
, data
, avl
, ndata
)
634 blobmsg_for_each_attr(attr
, tb
[UH_UBUS_SG_KEYS
], rem
)
636 if (blob_id(attr
) != BLOBMSG_TYPE_STRING
)
639 data
= avl_find_element(&ses
->data
, blobmsg_data(attr
), data
, avl
);
644 avl_delete(&ses
->data
, &data
->avl
);
653 uh_ubus_handle_destroy(struct ubus_context
*ctx
, struct ubus_object
*obj
,
654 struct ubus_request_data
*req
, const char *method
,
655 struct blob_attr
*msg
)
657 struct uh_ubus_state
*state
= container_of(obj
, struct uh_ubus_state
, ubus
);
658 struct uh_ubus_session
*ses
;
659 struct blob_attr
*tb
[__UH_UBUS_SA_MAX
];
661 blobmsg_parse(sid_policy
, __UH_UBUS_SI_MAX
, tb
, blob_data(msg
), blob_len(msg
));
663 if (!tb
[UH_UBUS_SI_SID
])
664 return UBUS_STATUS_INVALID_ARGUMENT
;
666 ses
= uh_ubus_session_get(state
, blobmsg_data(tb
[UH_UBUS_SI_SID
]));
669 return UBUS_STATUS_NOT_FOUND
;
671 uh_ubus_session_destroy(state
, ses
);
677 struct uh_ubus_state
*
678 uh_ubus_init(const struct config
*conf
)
681 struct uh_ubus_state
*state
;
682 struct ubus_object
*session_object
;
684 static struct ubus_method session_methods
[] = {
685 UBUS_METHOD("create", uh_ubus_handle_create
, new_policy
),
686 UBUS_METHOD("list", uh_ubus_handle_list
, sid_policy
),
687 UBUS_METHOD("grant", uh_ubus_handle_grant
, acl_policy
),
688 UBUS_METHOD("revoke", uh_ubus_handle_revoke
, acl_policy
),
689 UBUS_METHOD("set", uh_ubus_handle_set
, set_policy
),
690 UBUS_METHOD("get", uh_ubus_handle_get
, get_policy
),
691 UBUS_METHOD("unset", uh_ubus_handle_unset
, get_policy
),
692 UBUS_METHOD("destroy", uh_ubus_handle_destroy
, sid_policy
),
695 static struct ubus_object_type session_type
=
696 UBUS_OBJECT_TYPE("uhttpd", session_methods
);
698 state
= malloc(sizeof(*state
));
702 fprintf(stderr
, "Unable to allocate memory for ubus state\n");
706 memset(state
, 0, sizeof(*state
));
707 state
->ctx
= ubus_connect(conf
->ubus_socket
);
708 state
->timeout
= conf
->script_timeout
;
712 fprintf(stderr
, "Unable to connect to ubus socket\n");
716 ubus_add_uloop(state
->ctx
);
718 session_object
= &state
->ubus
;
719 session_object
->name
= "session";
720 session_object
->type
= &session_type
;
721 session_object
->methods
= session_methods
;
722 session_object
->n_methods
= ARRAY_SIZE(session_methods
);
724 rv
= ubus_add_object(state
->ctx
, &state
->ubus
);
728 fprintf(stderr
, "Unable to publish ubus object: %s\n",
733 blob_buf_init(&state
->buf
, 0);
734 avl_init(&state
->sessions
, uh_ubus_avlcmp
, false, NULL
);
741 uh_ubus_request_parse_url(struct client
*cl
, char **sid
, char **obj
, char **fun
)
743 char *url
= cl
->request
.url
+ strlen(cl
->server
->conf
->ubus_prefix
);
745 for (; url
&& *url
== '/'; *url
++ = 0);
748 for (url
= url
? strchr(url
, '/') : NULL
; url
&& *url
== '/'; *url
++ = 0);
751 for (url
= url
? strchr(url
, '/') : NULL
; url
&& *url
== '/'; *url
++ = 0);
754 for (url
= url
? strchr(url
, '/') : NULL
; url
&& *url
== '/'; *url
++ = 0);
755 return (*sid
&& *obj
&& *fun
);
759 uh_ubus_request_parse_post(struct client
*cl
, int len
, struct blob_buf
*b
)
763 char buf
[UH_LIMIT_MSGHEAD
];
765 struct json_object
*obj
= NULL
;
766 struct json_tokener
*tok
= NULL
;
771 memset(b
, 0, sizeof(*b
));
774 tok
= json_tokener_new();
778 /* remaining data in http head buffer ... */
779 if (cl
->httpbuf
.len
> 0)
781 rlen
= min(len
, cl
->httpbuf
.len
);
783 D("ubus: feed %d HTTP buffer bytes\n", rlen
);
785 memcpy(buf
, cl
->httpbuf
.ptr
, rlen
);
787 cl
->httpbuf
.len
-= rlen
;
788 cl
->httpbuf
.ptr
+= rlen
;
791 /* read it from socket ... */
794 ensure_out(rlen
= uh_tcp_recv(cl
, buf
, min(len
, sizeof(buf
))));
796 if ((rlen
< 0) && ((errno
== EAGAIN
) || (errno
== EWOULDBLOCK
)))
799 D("ubus: feed %d/%d TCP socket bytes\n",
800 rlen
, min(len
, sizeof(buf
)));
803 obj
= json_tokener_parse_ex(tok
, buf
, rlen
);
806 if (tok
->err
!= json_tokener_continue
&& !is_error(obj
))
813 if (json_object_get_type(obj
) == json_type_object
)
816 json_object_object_foreach(obj
, key
, val
)
818 if (!blobmsg_add_json_element(b
, key
, val
))
826 json_object_put(obj
);
829 json_tokener_free(tok
);
838 uh_ubus_request_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
842 struct client
*cl
= (struct client
*)req
->priv
;
846 uh_http_sendhf(cl
, 204, "No content", "Function did not return data\n");
850 str
= blobmsg_format_json_indent(msg
, true, 0);
853 ensure_out(uh_http_sendf(cl
, NULL
, "HTTP/1.0 200 OK\r\n"));
854 ensure_out(uh_http_sendf(cl
, NULL
, "Content-Type: application/json\r\n"));
855 ensure_out(uh_http_sendf(cl
, NULL
, "Content-Length: %i\r\n\r\n", len
));
856 ensure_out(uh_http_send(cl
, NULL
, str
, len
));
863 uh_ubus_request(struct client
*cl
, struct uh_ubus_state
*state
)
867 char *sid
, *obj
, *fun
;
870 struct uh_ubus_session
*ses
;
871 struct uh_ubus_session_acl
*acl
;
876 memset(&buf
, 0, sizeof(buf
));
877 blob_buf_init(&buf
, 0);
879 if (!uh_ubus_request_parse_url(cl
, &sid
, &obj
, &fun
))
881 uh_http_sendhf(cl
, 400, "Bad Request", "Invalid Request\n");
885 if (!(ses
= uh_ubus_session_get(state
, sid
)))
887 uh_http_sendhf(cl
, 404, "Not Found", "No such session\n");
891 avl_for_each_element(&ses
->acls
, acl
, avl
)
893 if (uh_ubus_strmatch(obj
, acl
->object
) &&
894 uh_ubus_strmatch(fun
, acl
->function
))
903 uh_http_sendhf(cl
, 403, "Denied", "Access to object denied\n");
907 /* find content length */
908 if (cl
->request
.method
== UH_HTTP_MSG_POST
)
910 foreach_header(i
, cl
->request
.headers
)
912 if (!strcasecmp(cl
->request
.headers
[i
], "Content-Length"))
914 len
= atoi(cl
->request
.headers
[i
+1]);
920 if (len
> UH_UBUS_MAX_POST_SIZE
)
922 uh_http_sendhf(cl
, 413, "Too Large", "Message too big\n");
926 if (len
&& !uh_ubus_request_parse_post(cl
, len
, &buf
))
928 uh_http_sendhf(cl
, 400, "Bad Request", "Invalid JSON data\n");
932 if (ubus_lookup_id(state
->ctx
, obj
, &obj_id
))
934 uh_http_sendhf(cl
, 500, "Internal Error", "Unable to lookup object\n");
938 if (ubus_invoke(state
->ctx
, obj_id
, fun
, buf
.head
,
939 uh_ubus_request_cb
, cl
, state
->timeout
* 1000))
941 uh_http_sendhf(cl
, 500, "Internal Error", "Unable to invoke function\n");
951 uh_ubus_close(struct uh_ubus_state
*state
)
954 ubus_free(state
->ctx
);