Initial upload.

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@10705 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Eric des Courtis 2008-12-10 21:43:26 +00:00
parent 41406abce5
commit 850c5cb368
24 changed files with 4053 additions and 0 deletions

View File

@ -0,0 +1,5 @@
BASE=../../../..
LOCAL_SOURCES=arraylist.c debug.c json_object.c json_tokener.c json_util.c linkhash.c printbuf.c url_encoding.c http_req.c
LOCAL_OBJS=arraylist.o debug.o json_object.o json_tokener.o json_util.o linkhash.o printbuf.o url_encoding.o http_req.o
include $(BASE)/build/modmake.rules

View File

@ -0,0 +1,93 @@
/*
* $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#if STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#endif /* STDC_HEADERS */
#if HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include "bits.h"
#include "arraylist.h"
struct array_list*
array_list_new(array_list_free_fn *free_fn)
{
struct array_list *this;
if(!(this = calloc(1, sizeof(struct array_list)))) return NULL;
this->size = ARRAY_LIST_DEFAULT_SIZE;
this->length = 0;
this->free_fn = free_fn;
if(!(this->array = calloc(sizeof(void*), this->size))) {
free(this);
return NULL;
}
return this;
}
extern void
array_list_free(struct array_list *this)
{
int i;
for(i = 0; i < this->length; i++)
if(this->array[i]) this->free_fn(this->array[i]);
free(this->array);
free(this);
}
void*
array_list_get_idx(struct array_list *this, int i)
{
if(i >= this->length) return NULL;
return this->array[i];
}
static int array_list_expand_internal(struct array_list *this, int max)
{
void *t;
int new_size;
if(max < this->size) return 0;
new_size = max(this->size << 1, max);
if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1;
this->array = t;
(void)memset(this->array + this->size, 0, (new_size-this->size)*sizeof(void*));
this->size = new_size;
return 0;
}
int
array_list_put_idx(struct array_list *this, int idx, void *data)
{
if(array_list_expand_internal(this, idx)) return -1;
if(this->array[idx]) this->free_fn(this->array[idx]);
this->array[idx] = data;
if(this->length <= idx) this->length = idx + 1;
return 0;
}
int
array_list_add(struct array_list *this, void *data)
{
return array_list_put_idx(this, this->length, data);
}
int
array_list_length(struct array_list *this)
{
return this->length;
}

View File

@ -0,0 +1,45 @@
/*
* $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _arraylist_h_
#define _arraylist_h_
#define ARRAY_LIST_DEFAULT_SIZE 32
typedef void (array_list_free_fn) (void *data);
struct array_list
{
void **array;
int length;
int size;
array_list_free_fn *free_fn;
};
extern struct array_list*
array_list_new(array_list_free_fn *free_fn);
extern void
array_list_free(struct array_list *al);
extern void*
array_list_get_idx(struct array_list *al, int i);
extern int
array_list_put_idx(struct array_list *al, int i, void *data);
extern int
array_list_add(struct array_list *al, void *data);
extern int
array_list_length(struct array_list *al);
#endif

View File

@ -0,0 +1,27 @@
/*
* $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _bits_h_
#define _bits_h_
#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
#define error_ptr(error) ((void*)error)
#define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L)
#endif

View File

@ -0,0 +1,118 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
/* #undef HAVE_DOPRNT */
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `open' function. */
#define HAVE_OPEN 1
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
and to 0 otherwise. */
#define HAVE_REALLOC 1
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strncasecmp' function. */
#define HAVE_STRNCASECMP 1
/* Define to 1 if you have the `strndup' function. */
#define HAVE_STRNDUP 1
/* Define to 1 if you have the <syslog.h> header file. */
#define HAVE_SYSLOG_H 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vasprintf' function. */
#define HAVE_VASPRINTF 1
/* Define to 1 if you have the `vprintf' function. */
#define HAVE_VPRINTF 1
/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1
/* Define to 1 if you have the `vsyslog' function. */
#define HAVE_VSYSLOG 1
/* Name of package */
#define PACKAGE ""
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "michael@metaparadigm.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "JSON C Library"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "JSON C Library 0.3"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "json-c"
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.3"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.3"
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to rpl_realloc if the replacement function should be used. */
/* #undef realloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

View File

@ -0,0 +1,94 @@
/*
* $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#if HAVE_SYSLOG_H
# include <syslog.h>
#endif /* HAVE_SYSLOG_H */
#if HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif /* HAVE_SYS_PARAM_H */
#include "debug.h"
static int _syslog = 0;
static int _debug = 0;
void mc_set_debug(int debug) { _debug = debug; }
int mc_get_debug() { return _debug; }
extern void mc_set_syslog(int syslog)
{
_syslog = syslog;
}
void mc_abort(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_ERR, msg, ap);
} else
#endif
vprintf(msg, ap);
exit(1);
}
void mc_debug(const char *msg, ...)
{
va_list ap;
if(_debug) {
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_DEBUG, msg, ap);
} else
#endif
vprintf(msg, ap);
}
}
void mc_error(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_ERR, msg, ap);
} else
#endif
vfprintf(stderr, msg, ap);
}
void mc_info(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_INFO, msg, ap);
} else
#endif
vfprintf(stderr, msg, ap);
}

View File

@ -0,0 +1,24 @@
/*
* $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _DEBUG_H_
#define _DEBUG_H_
extern void mc_set_debug(int debug);
extern int mc_get_debug();
extern void mc_set_syslog(int syslog);
extern void mc_abort(const char *msg, ...);
extern void mc_debug(const char *msg, ...);
extern void mc_error(const char *msg, ...);
extern void mc_info(const char *msg, ...);
#endif

View File

@ -0,0 +1,680 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2008, Eric des Courtis <eric.des.courtis@benbria.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Eric des Courtis <eric.des.courtis@benbria.com>
* Copyright (C) Benbria. All Rights Reserved.
*
* Contributor(s):
*
* Eric des Courtis <eric.des.courtis@benbria.com>
*
*
* http_req.c -- HTTP client implementation
*
*/
#include "http_req.h"
/*
extern int dprintf(int, const char *, ...);
extern int isblank(int);
*/
/* NOTE: v = version, header = h, status = s, newline = n, phrase = p */
static accept_state_t state_start(char c, state_machine_t *sm);
static accept_state_t state_shp (char c, state_machine_t *sm);
static accept_state_t state_n (char c, state_machine_t *sm);
static accept_state_t state_vhp_A(char c, state_machine_t *sm);
static accept_state_t state_vhp_B(char c, state_machine_t *sm);
static accept_state_t state_vhp_C(char c, state_machine_t *sm);
static accept_state_t state_vhp_D(char c, state_machine_t *sm);
static accept_state_t state_vhp_E(char c, state_machine_t *sm);
static accept_state_t state_vhp_F(char c, state_machine_t *sm);
static accept_state_t state_vhp_G(char c, state_machine_t *sm);
static accept_state_t state_vhp_H(char c, state_machine_t *sm);
static accept_state_t state_hp_A (char c, state_machine_t *sm);
static accept_state_t state_hp_B (char c, state_machine_t *sm);
static accept_state_t state_p (char c, state_machine_t *sm);
static accept_state_t state_error(char c, state_machine_t *sm);
static int read_all(int s, char *buf, size_t len);
#ifdef DEBUG
int main(int argc, char *argv[])
{
http_response_t response;
http_request_t request;
int ret;
int i;
if(argc != 2) return EXIT_FAILURE;
request.method = GET;
request.version = DEFAULT_HTTP_VERSION;
request.url = argv[1];
request.header_len = 0;
request.body_len = 0;
ret = http_req(&request, &response);
if(ret == ERROR) return EXIT_FAILURE;
printf("Version : %s\n", response.version);
printf("Status Code : %d\n", response.status_code);
printf("Phrase : %s\n", response.phrase);
for(i = 0; i < response.header_len; i++){
printf(
"Header : key = [%s] value = [%s]\n",
response.headers[i].field_name, response.headers[i].value
);
}
fflush(stdout);
write(STDOUT_FILENO, response.body, response.body_len);
printf("\n");
free_http_response(&response);
return EXIT_SUCCESS;
}
#endif
int http_req(http_request_t *req, http_response_t *res)
{
uint32_t addr;
int s;
int ret;
uint16_t port = 0;
size_t len;
struct sockaddr_in sck;
struct hostent *hst;
char *hostname;
char *method;
char *buf;
int buf_len;
ssize_t i;
int j;
int l;
int m;
int p;
int q = 0;
char f = HTTP_FALSE;
char port_s[MAX_PORT_LEN];
sighandler_t sig;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
(void)memset(&sck, 0, sizeof(sck));
sig = signal(SIGPIPE, SIG_IGN);
if(sig == SIG_ERR){
fprintf(stderr, "Cannot ignore SIGPIPE signal\n");
return ERROR;
}
s = socket(PF_INET, SOCK_STREAM, 0);
if(s == ERROR){
perror("Could not create socket");
return ERROR;
}
(void)setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
(void)setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
len = strlen(req->url);
hostname = (char *)malloc(len * sizeof(char) + 1);
if(hostname == NULL){
perror("Could not allocate memory for hostname");
close(s);
return ERROR;
}
EMPTY_STRING(hostname);
l = strlen(req->url) + 1;
m = strlen("http://");
for(p = 0, j = m; j < l; j++){
if(req->url[j] == ':'){
strncpy(hostname, req->url + m, j - m);
hostname[j - m] = '\0';
f = HTTP_TRUE;
p = j;
continue;
}
if((req->url[j] == '/' || req->url[j] == '\0') && f == HTTP_TRUE){
if((j - p) < MAX_PORT_LEN){
strncpy(port_s, req->url + p + 1, j - p);
port_s[j - p] = '\0';
port = (uint16_t)atoi(port_s);
}else port = 0;
q = j;
break;
}
if((req->url[j] == '/' || req->url[j] == '\0') && f == HTTP_FALSE){
strncpy(hostname, req->url + m, j - m);
hostname[j - m] = '\0';
port = DEFAULT_HTTP_PORT;
q = j;
break;
}
}
if(port == 0 || hostname[0] == '\0'){
fprintf(stderr, "Invalid URL\n");
close(s);
free(hostname);
return ERROR;
}
l = strlen(hostname);
for(j = 0; j < l; j++){
if(hostname[j] == '/'){
hostname[j] = '\0';
break;
}
}
hst = gethostbyname(hostname);
if(hst == NULL){
herror("Could not find host");
close(s);
free(hostname);
return ERROR;
}
addr = *((uint32_t *)hst->h_addr_list[0]);
sck.sin_family = AF_INET;
sck.sin_port = htons(port);
sck.sin_addr.s_addr = addr;
ret = connect(s, (struct sockaddr *)&sck, sizeof(sck));
if(ret == ERROR){
perror("Could not connect to host");
close(s);
free(hostname);
return ERROR;
}
switch(req->method){
case GET:
method = HTTP_GET_METHOD;
break;
case HEAD:
method = HTTP_HEAD_METHOD;
break;
case POST:
method = HTTP_POST_METHOD;
break;
case DELETE:
method = HTTP_DELETE_METHOD;
break;
case PUT:
method = HTTP_PUT_METHOD;
break;
default:
method = HTTP_GET_METHOD;
}
if(req->url[q] == '/'){
dprintf(s, "%s %s HTTP/%s\r\n", method, req->url + q, req->version);
}else{
dprintf(s, "%s /%s HTTP/%s\r\n", method, req->url + q, req->version);
}
if(port != DEFAULT_HTTP_PORT)
dprintf(s, "Host: %s:%d\r\n", hostname, port);
else dprintf(s, "Host: %s\r\n", hostname);
dprintf(s, "Connection: close\r\n");
dprintf(s, "Content-Length: %d\r\n", req->body_len);
for(i = 0; i < req->header_len; i++){
dprintf(
s,
"%s: %s\r\n",
req->headers[i].field_name,
req->headers[i].value
);
}
dprintf(s, "\r\n");
if(req->body != NULL && req->body_len != 0){
ret = write(s, req->body, req->body_len);
if(ret == ERROR){
perror("Could not write body to socket");
free(hostname);
return ERROR;
}
}
buf = (char *)malloc(RECV_BUFF_SIZE * sizeof(char));
if(buf == NULL){
perror("Could not allocate memory for buffer");
close(s);
free(hostname);
return ERROR;
}
buf_len = read_all(s, buf, RECV_BUFF_SIZE -1);
if(buf_len == ERROR){
perror("Could not read into buffer");
free(hostname);
return ERROR;
}
buf[buf_len] = '\0';
close(s);
(void)signal(SIGPIPE, sig);
free(hostname);
return http_parse_response(buf, buf_len, res);
}
int http_parse_response(char *buf, ssize_t buf_len, http_response_t *response)
{
token_t token;
state_machine_t sm;
int pos;
ssize_t size;
char buff[STATUS_CODE_LEN];
int old_pos;
int nt;
int i;
int j;
int f;
INIT_STATE_MACHINE(&sm);
sm.buf = buf;
sm.buf_len = buf_len;
pos = sm.pos;
token = get_next_token(&sm);
if(token != VERSION){
fprintf(stderr, "ERROR %d-%d\n", VERSION, token);
return ERROR;
}
size = sm.pos - pos;
response->version = (char *)malloc((size + 1) * sizeof(char));
if(response->version == NULL){
perror("Cannot allocate memory for version number");
return ERROR;
}
strncpy(response->version, sm.buf + pos, size);
response->version[size] = '\0';
pos = sm.pos;
token = get_next_token(&sm);
if(token != STATUS_CODE){
fprintf(stderr, "ERROR %d-%d\n", STATUS_CODE, token);
return ERROR;
}
size = sm.pos - pos;
buff[STATUS_CODE_LEN - 1] = '\0';
strncpy(buff, sm.buf + pos, STATUS_CODE_LEN - 1);
response->status_code = atoi(buff);
pos = sm.pos;
token = get_next_token(&sm);
if(token != PHRASE){
fprintf(stderr, "ERROR %d-%d\n", PHRASE, token);
return ERROR;
}
size = sm.pos - pos - 2;
response->phrase = (char *)malloc((size + 1) * sizeof(char));
if(response->phrase == NULL){
perror("Cannot allocate memory for phrase");
return ERROR;
}
strncpy(response->phrase, sm.buf + pos, size);
response->phrase[size] = '\0';
old_pos = sm.pos;
nt = 0;
f = HTTP_FALSE;
do{
token = get_next_token(&sm);
switch(token){
case PHRASE:
case STATUS_CODE:
f = HTTP_FALSE;
case VERSION:
case NEWLINE:
break;
case HEADER:
if(f == HTTP_FALSE){
nt++;
f = HTTP_TRUE;
}
else f = HTTP_FALSE;
break;
case SYNTAX_ERROR:
return ERROR;
}
if(token != HEADER && token != PHRASE && token != STATUS_CODE) break;
}while(token != SYNTAX_ERROR);
if(nt != 0){
response->headers = (http_header_t *)malloc(sizeof(http_header_t)*nt);
if(response->headers == NULL){
perror("Could not allocate memory for headers");
return ERROR;
}
}else response->headers = NULL;
response->header_len = nt;
sm.pos = old_pos;
for(i = 0; i < nt; i++){
pos = sm.pos;
sm.state = state_start;
sm.stop = HTTP_FALSE;
token = get_next_token(&sm);
size = sm.pos - pos;
size -= 2;
response->headers[i].field_name =
(char *)malloc((size + 1) * sizeof(char));
if(response->headers[i].field_name == NULL){
perror("Could not allocate memory for header");
return ERROR;
}
strncpy(response->headers[i].field_name, sm.buf + pos, size);
response->headers[i].field_name[size] = '\0';
pos = sm.pos;
token = get_next_token(&sm);
if(token == HEADER || token == STATUS_CODE){
for(j = 0;
((sm.buf + pos)[j] == '\r'
&& (sm.buf + pos)[j + 1] == '\n') == 0;
j++
);
size = j;
sm.pos = j + 2;
}else size = sm.pos - pos - 2;
response->headers[i].value =
(char *)malloc((size + 1) * sizeof(char));
if(response->headers[i].value == NULL){
perror("Could not allocate memory for header");
return ERROR;
}
strncpy(response->headers[i].value, sm.buf + pos, size);
response->headers[i].value[size] = '\0';
}
pos = sm.pos;
token = get_next_token(&sm);
if(token != NEWLINE){
fprintf(stderr, "ERROR %d-%d\n", NEWLINE, token);
return ERROR;
}
response->body = (char *)malloc((buf_len - sm.pos + 1) * sizeof(char));
if(response->body == NULL){
perror("Could not allocate memory for body");
return ERROR;
}
response->body_len = buf_len - sm.pos;
response->body[response->body_len] = '\0';
(void)memcpy(response->body, buf + sm.pos, response->body_len);
return SUCCESS;
}
void free_http_response(http_response_t *response)
{
free(response->version);
free(response->phrase);
if(response->headers != NULL) free(response->headers);
if(response->body != NULL) free(response->body);
}
token_t get_next_token(state_machine_t *sm)
{
char c;
accept_state_t accept;
while(sm->stop != HTTP_TRUE){
c = sm->buf[sm->pos];
accept = sm->state(c, sm);
switch(accept){
case NOAS:
case ASNR:
sm->pos++;
case ASWR:
break;
}
switch(accept){
case ASNR:
case ASWR:
sm->state = state_start;
return sm->token;
case NOAS:
break;
}
if(sm->pos >= sm->buf_len){
sm->stop = HTTP_TRUE;
break;
}
}
return SYNTAX_ERROR;
}
static accept_state_t state_start(char c, state_machine_t *sm)
{
if(toupper(c) == 'H') sm->state = state_vhp_A;
else if(isdigit(c)) sm->state = state_shp;
else if(c == '\r' || c == '\n') sm->state = state_n;
else if(isprint(c)) sm->state = state_hp_A;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_shp(char c, state_machine_t *sm)
{
if(isdigit(c)) sm->state = state_shp;
else if(isblank(c)){
sm->token = STATUS_CODE;
return ASNR;
}else if(c == ':') sm->state = state_hp_B;
else if(c == '\r' || c == '\n') sm->state = state_p;
else if(isprint(c)) sm->state = state_hp_A;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_n(char c, state_machine_t *sm)
{
if(c == '\r' || c == '\n'){
sm->token = NEWLINE;
return ASNR;
}else if(c == ':') sm->state = state_hp_B;
else if(isprint(c)) sm->state = state_hp_A;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_A(char c, state_machine_t *sm)
{
if(toupper(c) == 'T') sm->state = state_vhp_B;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_B(char c, state_machine_t *sm)
{
if(toupper(c) == 'T') sm->state = state_vhp_C;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_C(char c, state_machine_t *sm)
{
if(toupper(c) == 'P') sm->state = state_vhp_D;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_D(char c, state_machine_t *sm)
{
if(toupper(c) == '/') sm->state = state_vhp_E;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_E(char c, state_machine_t *sm)
{
if(isdigit(c)) sm->state = state_vhp_F;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_F(char c, state_machine_t *sm)
{
if(isdigit(c)) sm->state = state_vhp_F;
else if(c == '.') sm->state = state_vhp_G;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_G(char c, state_machine_t *sm)
{
if(isdigit(c)) sm->state = state_vhp_H;
else if(isprint(c)) sm->state = state_hp_A;
else if(c == '\n' || c == '\r') sm->state = state_p;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_vhp_H(char c, state_machine_t *sm)
{
if(isdigit(c)) sm->state = state_vhp_H;
else if(isblank(c)){
sm->token = VERSION;
return ASNR;
}else if(isprint(c)) sm->state = state_hp_A;
return NOAS;
}
static accept_state_t state_hp_A(char c, state_machine_t *sm)
{
if(c == ':') sm->state = state_hp_B;
else if(c == '\r' || c == '\n') sm->state = state_p;
else if(isprint(c)) sm->state = state_hp_A;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_hp_B(char c, state_machine_t *sm)
{
if(isblank(c)){
sm->token = HEADER;
return ASNR;
} else if(c == '\r' || c == '\n') sm->state = state_p;
else if(c == ':') sm->state = state_hp_B;
else if(isprint(c)) sm->state = state_hp_A;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_p(char c, state_machine_t *sm)
{
if(c == '\r' || c == '\n'){
sm->token = PHRASE;
return ASNR;
}else if(c == ':') sm->state = state_hp_B;
else if(isprint(c)) sm->state = state_hp_A;
else sm->state = state_error;
return NOAS;
}
static accept_state_t state_error(char c, state_machine_t *sm)
{
c = 0;
sm->token = SYNTAX_ERROR;
return ASNR;
}
static int read_all(int s, char *buf, size_t len)
{
size_t t;
size_t r = ERROR;
for(t = 0; t < len && r != 0;){
r = read(s, buf + t, len - t);
if((int)r == ERROR){
return ERROR;
}else{
t += r;
}
}
return (int)t;
}

View File

@ -0,0 +1,138 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2008, Eric des Courtis <eric.des.courtis@benbria.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Eric des Courtis <eric.des.courtis@benbria.com>
* Copyright (C) Benbria. All Rights Reserved.
*
* Contributor(s):
*
* Eric des Courtis <eric.des.courtis@benbria.com>
*
*
* http_req.h -- HTTP client implementation
*
*/
#ifndef __HTTP_REQ_H__
#define __HTTP_REQ_H__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#define ERROR -1
#define SUCCESS 0
#define EMPTY_STRING(s) s[0] = '\0'
#define DEFAULT_HTTP_VERSION "1.1"
#define DEFAULT_HTTP_PORT 80
#define HTTP_GET_METHOD "GET"
#define HTTP_HEAD_METHOD "HEAD"
#define HTTP_POST_METHOD "POST"
#define HTTP_DELETE_METHOD "DELETE"
#define HTTP_PUT_METHOD "PUT"
#define MAX_PORT_LEN 6
#define RECV_BUFF_SIZE 65536
#define HTTP_TRUE 1
#define HTTP_FALSE 0
#define INIT_STATE_MACHINE(m) \
do {\
(m)->pos = 0;\
(m)->buf = NULL;\
(m)->token = SYNTAX_ERROR;\
(m)->stop = HTTP_FALSE;\
(m)->state = state_start;\
} while(0)
#define STATUS_CODE_LEN 4
typedef enum tokens {
VERSION,
STATUS_CODE,
PHRASE,
HEADER,
NEWLINE,
SYNTAX_ERROR
} token_t;
typedef enum accept_states {
ASWR,
ASNR,
NOAS
} accept_state_t;
typedef struct state_machines {
accept_state_t (*state)(char, struct state_machines *);
int pos;
char *buf;
ssize_t buf_len;
int stop;
token_t token;
} state_machine_t;
typedef enum http_methods {
GET,
HEAD,
POST,
DELETE,
PUT
} http_method_t;
typedef struct http_headers {
char *field_name;
char *value;
} http_header_t;
typedef struct http_requests {
http_method_t method;
char *version;
char *url;
http_header_t *headers;
ssize_t header_len;
char *body;
ssize_t body_len;
} http_request_t;
typedef struct http_responses {
char *version;
int status_code;
char *phrase;
http_header_t *headers;
ssize_t header_len;
char *body;
int body_len;
} http_response_t;
token_t get_next_token(state_machine_t *sm);
int http_parse_response(char *buf, ssize_t buf_len, http_response_t *response);
int http_req(http_request_t *req, http_response_t *res);
void free_http_response(http_response_t *response);
#endif

View File

@ -0,0 +1,31 @@
/*
* $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _json_h_
#define _json_h_
#ifdef __cplusplus
extern "C" {
#endif
#include "bits.h"
#include "debug.h"
#include "linkhash.h"
#include "arraylist.h"
#include "json_util.h"
#include "json_object.h"
#include "json_tokener.h"
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,510 @@
/*
* $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "printbuf.h"
#include "linkhash.h"
#include "arraylist.h"
#include "json_object.h"
#include "json_object_private.h"
#include "json_tokener.h"
#if !HAVE_STRNDUP
char* strndup(const char* str, size_t n);
#endif /* !HAVE_STRNDUP */
/* #define REFCOUNT_DEBUG 1 */
char *json_number_chars = "0123456789.+-e";
char *json_hex_chars = "0123456789abcdef";
#ifdef REFCOUNT_DEBUG
static char* json_type_name[] = {
"null",
"boolean",
"double",
"int",
"object",
"array",
"string",
};
#endif /* REFCOUNT_DEBUG */
static void json_object_generic_delete(struct json_object* this);
static struct json_object* json_object_new(enum json_type o_type);
/* ref count debugging */
#ifdef REFCOUNT_DEBUG
static struct lh_table *json_object_table;
static void json_object_init() __attribute__ ((constructor));
static void json_object_init() {
mc_debug("json_object_init: creating object table\n");
json_object_table = lh_kptr_table_new(128, "json_object_table", NULL);
}
static void json_object_fini() __attribute__ ((destructor));
static void json_object_fini() {
struct lh_entry *ent;
if(mc_get_debug() && json_object_table->count) {
mc_debug("json_object_fini: %d referenced objects at exit\n",
json_object_table->count);
lh_foreach(json_object_table, ent) {
struct json_object* obj = (struct json_object*)ent->v;
mc_debug("\t%s:%p\n", json_type_name[obj->o_type], obj);
}
}
mc_debug("json_object_fini: freeing object table\n");
lh_table_free(json_object_table);
}
#endif /* REFCOUNT_DEBUG */
/* string escaping */
static int json_escape_str(struct printbuf *pb, char *str)
{
int pos = 0, start_offset = 0;
unsigned char c;
do {
c = str[pos];
switch(c) {
case '\0':
break;
case '\b':
case '\n':
case '\r':
case '\t':
case '"':
case '\\':
case '/':
if(pos - start_offset > 0)
printbuf_memappend(pb, str + start_offset, pos - start_offset);
if(c == '\b') printbuf_memappend(pb, "\\b", 2);
else if(c == '\n') printbuf_memappend(pb, "\\n", 2);
else if(c == '\r') printbuf_memappend(pb, "\\r", 2);
else if(c == '\t') printbuf_memappend(pb, "\\t", 2);
else if(c == '"') printbuf_memappend(pb, "\\\"", 2);
else if(c == '\\') printbuf_memappend(pb, "\\\\", 2);
else if(c == '/') printbuf_memappend(pb, "\\/", 2);
start_offset = ++pos;
break;
default:
if(c < ' ') {
if(pos - start_offset > 0)
printbuf_memappend(pb, str + start_offset, pos - start_offset);
sprintbuf(pb, "\\u00%c%c",
json_hex_chars[c >> 4],
json_hex_chars[c & 0xf]);
start_offset = ++pos;
} else pos++;
}
} while(c);
if(pos - start_offset > 0)
printbuf_memappend(pb, str + start_offset, pos - start_offset);
return 0;
}
/* reference counting */
extern struct json_object* json_object_get(struct json_object *this)
{
if(this) {
this->_ref_count++;
}
return this;
}
extern void json_object_put(struct json_object *this)
{
if(this) {
this->_ref_count--;
if(!this->_ref_count) this->_delete(this);
}
}
/* generic object construction and destruction parts */
static void json_object_generic_delete(struct json_object* this)
{
#ifdef REFCOUNT_DEBUG
mc_debug("json_object_delete_%s: %p\n",
json_type_name[this->o_type], this);
lh_table_delete(json_object_table, this);
#endif /* REFCOUNT_DEBUG */
printbuf_free(this->_pb);
free(this);
}
static struct json_object* json_object_new(enum json_type o_type)
{
struct json_object *this = calloc(sizeof(struct json_object), 1);
if(!this) return NULL;
this->o_type = o_type;
this->_ref_count = 1;
this->_delete = &json_object_generic_delete;
#ifdef REFCOUNT_DEBUG
lh_table_insert(json_object_table, this, this);
mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this);
#endif /* REFCOUNT_DEBUG */
return this;
}
/* type checking functions */
int json_object_is_type(struct json_object *this, enum json_type type)
{
return (this->o_type == type);
}
enum json_type json_object_get_type(struct json_object *this)
{
return this->o_type;
}
/* json_object_to_json_string */
char* json_object_to_json_string(struct json_object *this)
{
if(!this) return "null";
if(!this->_pb) {
if(!(this->_pb = printbuf_new())) return NULL;
} else {
printbuf_reset(this->_pb);
}
if(this->_to_json_string(this, this->_pb) < 0) return NULL;
return this->_pb->buf;
}
/* json_object_object */
static int json_object_object_to_json_string(struct json_object* this,
struct printbuf *pb)
{
int i=0;
struct json_object_iter iter;
sprintbuf(pb, "{");
/* CAW: scope operator to make ANSI correctness */
/* CAW: switched to json_object_object_foreachC which uses an iterator struct */
json_object_object_foreachC(this, iter) {
if(i) sprintbuf(pb, ",");
sprintbuf(pb, " \"");
json_escape_str(pb, iter.key);
sprintbuf(pb, "\": ");
if(iter.val == NULL) sprintbuf(pb, "null");
else iter.val->_to_json_string(iter.val, pb);
i++;
}
return sprintbuf(pb, " }");
}
static void json_object_lh_entry_free(struct lh_entry *ent)
{
free(ent->k);
json_object_put((struct json_object*)ent->v);
}
static void json_object_object_delete(struct json_object* this)
{
lh_table_free(this->o.c_object);
json_object_generic_delete(this);
}
struct json_object* json_object_new_object()
{
struct json_object *this = json_object_new(json_type_object);
if(!this) return NULL;
this->_delete = &json_object_object_delete;
this->_to_json_string = &json_object_object_to_json_string;
this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES,
NULL, &json_object_lh_entry_free);
return this;
}
struct lh_table* json_object_get_object(struct json_object *this)
{
if(!this) return NULL;
switch(this->o_type) {
case json_type_object:
return this->o.c_object;
default:
return NULL;
}
}
void json_object_object_add(struct json_object* this, char *key,
struct json_object *val)
{
lh_table_delete(this->o.c_object, key);
lh_table_insert(this->o.c_object, strdup(key), val);
}
struct json_object* json_object_object_get(struct json_object* this, char *key)
{
return (struct json_object*) lh_table_lookup(this->o.c_object, key);
}
void json_object_object_del(struct json_object* this, char *key)
{
lh_table_delete(this->o.c_object, key);
}
/* json_object_boolean */
static int json_object_boolean_to_json_string(struct json_object* this,
struct printbuf *pb)
{
if(this->o.c_boolean) return sprintbuf(pb, "true");
else return sprintbuf(pb, "false");
}
struct json_object* json_object_new_boolean(boolean b)
{
struct json_object *this = json_object_new(json_type_boolean);
if(!this) return NULL;
this->_to_json_string = &json_object_boolean_to_json_string;
this->o.c_boolean = b;
return this;
}
boolean json_object_get_boolean(struct json_object *this)
{
if(!this) return FALSE;
switch(this->o_type) {
case json_type_boolean:
return this->o.c_boolean;
case json_type_int:
return (this->o.c_int != 0);
case json_type_double:
return (this->o.c_double != 0);
case json_type_string:
if(strlen(this->o.c_string)) return TRUE;
default:
return TRUE;
}
}
/* json_object_int */
static int json_object_int_to_json_string(struct json_object* this,
struct printbuf *pb)
{
return sprintbuf(pb, "%d", this->o.c_int);
}
struct json_object* json_object_new_int(int i)
{
struct json_object *this = json_object_new(json_type_int);
if(!this) return NULL;
this->_to_json_string = &json_object_int_to_json_string;
this->o.c_int = i;
return this;
}
int json_object_get_int(struct json_object *this)
{
int cint;
if(!this) return 0;
switch(this->o_type) {
case json_type_int:
return this->o.c_int;
case json_type_double:
return (int)this->o.c_double;
case json_type_boolean:
return this->o.c_boolean;
case json_type_string:
if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint;
default:
return 0;
}
}
/* json_object_double */
static int json_object_double_to_json_string(struct json_object* this,
struct printbuf *pb)
{
return sprintbuf(pb, "%lf", this->o.c_double);
}
struct json_object* json_object_new_double(double d)
{
struct json_object *this = json_object_new(json_type_double);
if(!this) return NULL;
this->_to_json_string = &json_object_double_to_json_string;
this->o.c_double = d;
return this;
}
double json_object_get_double(struct json_object *this)
{
double cdouble;
if(!this) return 0.0;
switch(this->o_type) {
case json_type_double:
return this->o.c_double;
case json_type_int:
return this->o.c_int;
case json_type_boolean:
return this->o.c_boolean;
case json_type_string:
if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble;
default:
return 0.0;
}
}
/* json_object_string */
static int json_object_string_to_json_string(struct json_object* this,
struct printbuf *pb)
{
sprintbuf(pb, "\"");
json_escape_str(pb, this->o.c_string);
sprintbuf(pb, "\"");
return 0;
}
static void json_object_string_delete(struct json_object* this)
{
free(this->o.c_string);
json_object_generic_delete(this);
}
struct json_object* json_object_new_string(char *s)
{
struct json_object *this = json_object_new(json_type_string);
if(!this) return NULL;
this->_delete = &json_object_string_delete;
this->_to_json_string = &json_object_string_to_json_string;
this->o.c_string = strdup(s);
return this;
}
struct json_object* json_object_new_string_len(char *s, int len)
{
struct json_object *this = json_object_new(json_type_string);
if(!this) return NULL;
this->_delete = &json_object_string_delete;
this->_to_json_string = &json_object_string_to_json_string;
this->o.c_string = strndup(s, len);
return this;
}
char* json_object_get_string(struct json_object *this)
{
if(!this) return NULL;
switch(this->o_type) {
case json_type_string:
return this->o.c_string;
default:
return json_object_to_json_string(this);
}
}
/* json_object_array */
static int json_object_array_to_json_string(struct json_object* this,
struct printbuf *pb)
{
int i;
sprintbuf(pb, "[");
for(i=0; i < json_object_array_length(this); i++) {
struct json_object *val;
if(i) { sprintbuf(pb, ", "); }
else { sprintbuf(pb, " "); }
val = json_object_array_get_idx(this, i);
if(val == NULL) { sprintbuf(pb, "null"); }
else { val->_to_json_string(val, pb); }
}
return sprintbuf(pb, " ]");
}
static void json_object_array_entry_free(void *data)
{
json_object_put((struct json_object*)data);
}
static void json_object_array_delete(struct json_object* this)
{
array_list_free(this->o.c_array);
json_object_generic_delete(this);
}
struct json_object* json_object_new_array()
{
struct json_object *this = json_object_new(json_type_array);
if(!this) return NULL;
this->_delete = &json_object_array_delete;
this->_to_json_string = &json_object_array_to_json_string;
this->o.c_array = array_list_new(&json_object_array_entry_free);
return this;
}
struct array_list* json_object_get_array(struct json_object *this)
{
if(!this) return NULL;
switch(this->o_type) {
case json_type_array:
return this->o.c_array;
default:
return NULL;
}
}
int json_object_array_length(struct json_object *this)
{
return array_list_length(this->o.c_array);
}
int json_object_array_add(struct json_object *this,struct json_object *val)
{
return array_list_add(this->o.c_array, val);
}
int json_object_array_put_idx(struct json_object *this, int idx,
struct json_object *val)
{
return array_list_put_idx(this->o.c_array, idx, val);
}
struct json_object* json_object_array_get_idx(struct json_object *this,
int idx)
{
return (struct json_object*)array_list_get_idx(this->o.c_array, idx);
}

View File

@ -0,0 +1,308 @@
/*
* $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _json_object_h_
#define _json_object_h_
#define JSON_OBJECT_DEF_HASH_ENTIRES 16
#undef FALSE
#define FALSE ((boolean)0)
#undef TRUE
#define TRUE ((boolean)1)
extern char *json_number_chars;
extern char *json_hex_chars;
/* forward structure definitions */
typedef int boolean;
struct printbuf;
struct lh_table;
struct array_list;
struct json_object;
struct json_object_iter;
/* supported object types */
enum json_type {
json_type_null,
json_type_boolean,
json_type_double,
json_type_int,
json_type_object,
json_type_array,
json_type_string
};
/* reference counting functions */
/**
* Increment the reference count of json_object
* @param obj the json_object instance
*/
extern struct json_object* json_object_get(struct json_object *obj);
/**
* Decrement the reference count of json_object and free if it reaches zero
* @param obj the json_object instance
*/
extern void json_object_put(struct json_object *obj);
/**
* Check if the json_object is of a given type
* @param obj the json_object instance
* @param type one of:
json_type_boolean,
json_type_double,
json_type_int,
json_type_object,
json_type_array,
json_type_string,
*/
extern int json_object_is_type(struct json_object *obj, enum json_type type);
/**
* Get the type of the json_object
* @param obj the json_object instance
* @returns type being one of:
json_type_boolean,
json_type_double,
json_type_int,
json_type_object,
json_type_array,
json_type_string,
*/
extern enum json_type json_object_get_type(struct json_object *obj);
/** Stringify object to json format
* @param obj the json_object instance
* @returns a string in JSON format
*/
extern char* json_object_to_json_string(struct json_object *obj);
/* object type methods */
/** Create a new empty object
* @returns a json_object of type json_type_object
*/
extern struct json_object* json_object_new_object();
/** Get the hashtable of a json_object of type json_type_object
* @param obj the json_object instance
* @returns a linkhash
*/
extern struct lh_table* json_object_get_object(struct json_object *obj);
/** Add an object field to a json_object of type json_type_object
*
* The reference count will *not* be incremented. This is to make adding
* fields to objects in code more compact. If you want to retain a reference
* to an added object you must wrap the passed object with json_object_get
*
* @param obj the json_object instance
* @param key the object field name (a private copy will be duplicated)
* @param val a json_object or NULL member to associate with the given field
*/
extern void json_object_object_add(struct json_object* obj, char *key,
struct json_object *val);
/** Get the json_object associate with a given object field
* @param obj the json_object instance
* @param key the object field name
* @returns the json_object associated with the given field name
*/
extern struct json_object* json_object_object_get(struct json_object* obj,
char *key);
/** Delete the given json_object field
*
* The reference count will be decremented for the deleted object
*
* @param obj the json_object instance
* @param key the object field name
*/
extern void json_object_object_del(struct json_object* obj, char *key);
/** Iterate through all keys and values of an object
* @param obj the json_object instance
* @param key the local name for the char* key variable defined in the body
* @param val the local name for the json_object* object variable defined in the body
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
# define json_object_object_foreach(obj,key,val) \
for(entry = json_object_get_object(obj)->head; ({ if(entry) { key = (char*)entry->k; val = (struct json_object*)entry->v; } ; entry; }); entry = entry->next )
#else /* ANSI C or MSC */
# define json_object_object_foreach(obj,key,val) \
for(entry = json_object_get_object(obj)->head; (entry ? (key = (char*)entry->k, val = (struct json_object*)entry->v, entry) : 0); entry = entry->next)
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
/** Iterate through all keys and values of an object (ANSI C Safe)
* @param obj the json_object instance
* @param iter the object iterator
*/
#define json_object_object_foreachC(obj,iter) \
for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next)
/* Array type methods */
/** Create a new empty json_object of type json_type_array
* @returns a json_object of type json_type_array
*/
extern struct json_object* json_object_new_array();
/** Get the arraylist of a json_object of type json_type_array
* @param obj the json_object instance
* @returns an arraylist
*/
extern struct array_list* json_object_get_array(struct json_object *obj);
/** Get the length of a json_object of type json_type_array
* @param obj the json_object instance
* @returns an int
*/
extern int json_object_array_length(struct json_object *obj);
/** Add an element to the end of a json_object of type json_type_array
*
* The reference count will *not* be incremented. This is to make adding
* fields to objects in code more compact. If you want to retain a reference
* to an added object you must wrap the passed object with json_object_get
*
* @param obj the json_object instance
* @param val the json_object to be added
*/
extern int json_object_array_add(struct json_object *obj,
struct json_object *val);
/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array)
*
* The reference count will *not* be incremented. This is to make adding
* fields to objects in code more compact. If you want to retain a reference
* to an added object you must wrap the passed object with json_object_get
*
* The reference count of a replaced object will be decremented.
*
* The array size will be automatically be expanded to the size of the
* index if the index is larger than the current size.
*
* @param obj the json_object instance
* @param idx the index to insert the element at
* @param val the json_object to be added
*/
extern int json_object_array_put_idx(struct json_object *obj, int idx,
struct json_object *val);
/** Get the element at specificed index of the array (a json_object of type json_type_array)
* @param obj the json_object instance
* @param idx the index to get the element at
* @returns the json_object at the specified index (or NULL)
*/
extern struct json_object* json_object_array_get_idx(struct json_object *obj,
int idx);
/* boolean type methods */
/** Create a new empty json_object of type json_type_boolean
* @param b a boolean TRUE or FALSE (0 or 1)
* @returns a json_object of type json_type_boolean
*/
extern struct json_object* json_object_new_boolean(boolean b);
/** Get the boolean value of a json_object
*
* The type is coerced to a boolean if the passed object is not a boolean.
* integer and double objects will return FALSE if there value is zero
* or TRUE otherwise. If the passed object is a string it will return
* TRUE if it has a non zero length. If any other object type is passed
* TRUE will be returned if the object is not NULL.
*
* @param obj the json_object instance
* @returns a boolean
*/
extern boolean json_object_get_boolean(struct json_object *obj);
/* int type methods */
/** Create a new empty json_object of type json_type_int
* @param i the integer
* @returns a json_object of type json_type_int
*/
extern struct json_object* json_object_new_int(int i);
/** Get the int value of a json_object
*
* The type is coerced to a int if the passed object is not a int.
* double objects will return their integer conversion. Strings will be
* parsed as an integer. If no conversion exists then 0 is returned.
*
* @param obj the json_object instance
* @returns an int
*/
extern int json_object_get_int(struct json_object *obj);
/* double type methods */
/** Create a new empty json_object of type json_type_double
* @param d the double
* @returns a json_object of type json_type_double
*/
extern struct json_object* json_object_new_double(double d);
/** Get the double value of a json_object
*
* The type is coerced to a double if the passed object is not a double.
* integer objects will return their dboule conversion. Strings will be
* parsed as a double. If no conversion exists then 0.0 is returned.
*
* @param obj the json_object instance
* @returns an double
*/
extern double json_object_get_double(struct json_object *obj);
/* string type methods */
/** Create a new empty json_object of type json_type_string
*
* A copy of the string is made and the memory is managed by the json_object
*
* @param s the string
* @returns a json_object of type json_type_string
*/
extern struct json_object* json_object_new_string(char *s);
extern struct json_object* json_object_new_string_len(char *s, int len);
/** Get the string value of a json_object
*
* If the passed object is not of type json_type_string then the JSON
* representation of the object is returned.
*
* The returned string memory is managed by the json_object and will
* be freed when the reference count of the json_object drops to zero.
*
* @param obj the json_object instance
* @returns a string
*/
extern char* json_object_get_string(struct json_object *obj);
#endif

View File

@ -0,0 +1,44 @@
/*
* $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _json_object_private_h_
#define _json_object_private_h_
typedef void (json_object_delete_fn)(struct json_object *o);
typedef int (json_object_to_json_string_fn)(struct json_object *o,
struct printbuf *pb);
struct json_object
{
enum json_type o_type;
json_object_delete_fn *_delete;
json_object_to_json_string_fn *_to_json_string;
int _ref_count;
struct printbuf *_pb;
union data {
boolean c_boolean;
double c_double;
int c_int;
struct lh_table *c_object;
struct array_list *c_array;
char *c_string;
} o;
};
/* CAW: added for ANSI C iteration correctness */
struct json_object_iter
{
char *key;
struct json_object *val;
struct lh_entry *entry;
};
#endif

View File

@ -0,0 +1,520 @@
/*
* $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "bits.h"
#include "debug.h"
#include "printbuf.h"
#include "arraylist.h"
#include "json_object.h"
#include "json_tokener.h"
#if !HAVE_STRNCASECMP && defined(_MSC_VER)
/* MSC has the version as _strnicmp */
# define strncasecmp _strnicmp
#elif !HAVE_STRNCASECMP
# error You do not have strncasecmp on your system.
#endif /* HAVE_STRNCASECMP */
static const char* json_null_str = "null";
static const char* json_true_str = "true";
static const char* json_false_str = "false";
const char* json_tokener_errors[] = {
"success",
"continue",
"nesting to deep",
"unexpected end of data",
"unexpected character",
"null expected",
"boolean expected",
"number expected",
"array value separator ',' expected",
"quoted object property name expected",
"object property name separator ':' expected",
"object value separator ',' expected",
"invalid string sequence",
"expected comment",
};
struct json_tokener* json_tokener_new()
{
struct json_tokener *tok = calloc(1, sizeof(struct json_tokener));
tok->pb = printbuf_new();
json_tokener_reset(tok);
return tok;
}
void json_tokener_free(struct json_tokener *tok)
{
json_tokener_reset(tok);
if(tok) printbuf_free(tok->pb);
free(tok);
}
static void json_tokener_reset_level(struct json_tokener *tok, int depth)
{
tok->stack[depth].state = json_tokener_state_eatws;
tok->stack[depth].saved_state = json_tokener_state_start;
json_object_put(tok->stack[depth].current);
tok->stack[depth].current = NULL;
free(tok->stack[depth].obj_field_name);
tok->stack[depth].obj_field_name = NULL;
}
void json_tokener_reset(struct json_tokener *tok)
{
int i;
for(i = tok->depth; i >= 0; i--)
json_tokener_reset_level(tok, i);
tok->depth = 0;
tok->err = json_tokener_success;
}
struct json_object* json_tokener_parse(char *str)
{
struct json_tokener* tok;
struct json_object* obj;
tok = json_tokener_new();
obj = json_tokener_parse_ex(tok, str, -1);
if(tok->err != json_tokener_success)
obj = error_ptr(-tok->err);
json_tokener_free(tok);
return obj;
}
#if !HAVE_STRNDUP
/* CAW: compliant version of strndup() */
char* strndup(const char* str, size_t n)
{
if(str) {
size_t len = strlen(str);
size_t nn = min(len,n);
char* s = (char*)malloc(sizeof(char) * (nn + 1));
if(s) {
memcpy(s, str, nn);
s[nn] = '\0';
}
return s;
}
return NULL;
}
#endif
#define state tok->stack[tok->depth].state
#define saved_state tok->stack[tok->depth].saved_state
#define current tok->stack[tok->depth].current
#define obj_field_name tok->stack[tok->depth].obj_field_name
struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
char *str, int len)
{
struct json_object *obj = NULL;
char c;
tok->char_offset = 0;
tok->err = json_tokener_success;
do {
if(tok->char_offset == len) {
if(tok->depth == 0 && state == json_tokener_state_eatws &&
saved_state == json_tokener_state_finish)
tok->err = json_tokener_success;
else
tok->err = json_tokener_continue;
goto out;
}
c = *str;
redo_char:
switch(state) {
case json_tokener_state_eatws:
if(isspace(c)) {
/* okay */
} else if(c == '/') {
printbuf_reset(tok->pb);
printbuf_memappend(tok->pb, &c, 1);
state = json_tokener_state_comment_start;
} else {
state = saved_state;
goto redo_char;
}
break;
case json_tokener_state_start:
switch(c) {
case '{':
state = json_tokener_state_eatws;
saved_state = json_tokener_state_object_field_start;
current = json_object_new_object();
break;
case '[':
state = json_tokener_state_eatws;
saved_state = json_tokener_state_array;
current = json_object_new_array();
break;
case 'N':
case 'n':
state = json_tokener_state_null;
printbuf_reset(tok->pb);
tok->st_pos = 0;
goto redo_char;
case '"':
case '\'':
state = json_tokener_state_string;
printbuf_reset(tok->pb);
tok->quote_char = c;
break;
case 'T':
case 't':
case 'F':
case 'f':
state = json_tokener_state_boolean;
printbuf_reset(tok->pb);
tok->st_pos = 0;
goto redo_char;
/*
#if defined(__GNUC__)
case '0' ... '9':
#else
*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/*
#endif
*/
case '-':
state = json_tokener_state_number;
printbuf_reset(tok->pb);
tok->is_double = 0;
goto redo_char;
default:
tok->err = json_tokener_error_parse_unexpected;
goto out;
}
break;
case json_tokener_state_finish:
if(tok->depth == 0) goto out;
obj = json_object_get(current);
json_tokener_reset_level(tok, tok->depth);
tok->depth--;
goto redo_char;
case json_tokener_state_null:
printbuf_memappend(tok->pb, &c, 1);
if(strncasecmp(json_null_str, tok->pb->buf,
min(tok->st_pos+1, strlen(json_null_str))) == 0) {
if(tok->st_pos == strlen(json_null_str)) {
current = NULL;
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
}
} else {
tok->err = json_tokener_error_parse_null;
goto out;
}
tok->st_pos++;
break;
case json_tokener_state_comment_start:
if(c == '*') {
state = json_tokener_state_comment;
} else if(c == '/') {
state = json_tokener_state_comment_eol;
} else {
tok->err = json_tokener_error_parse_comment;
goto out;
}
printbuf_memappend(tok->pb, &c, 1);
break;
case json_tokener_state_comment:
if(c == '*') state = json_tokener_state_comment_end;
printbuf_memappend(tok->pb, &c, 1);
break;
case json_tokener_state_comment_eol:
if(c == '\n') {
mc_debug("json_tokener_comment: %s\n", tok->pb->buf);
state = json_tokener_state_eatws;
} else {
printbuf_memappend(tok->pb, &c, 1);
}
break;
case json_tokener_state_comment_end:
printbuf_memappend(tok->pb, &c, 1);
if(c == '/') {
mc_debug("json_tokener_comment: %s\n", tok->pb->buf);
state = json_tokener_state_eatws;
} else {
state = json_tokener_state_comment;
}
break;
case json_tokener_state_string:
if(c == tok->quote_char) {
current = json_object_new_string(tok->pb->buf);
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
} else if(c == '\\') {
saved_state = json_tokener_state_string;
state = json_tokener_state_string_escape;
} else {
printbuf_memappend(tok->pb, &c, 1);
}
break;
case json_tokener_state_string_escape:
switch(c) {
case '"':
case '\\':
case '/':
printbuf_memappend(tok->pb, &c, 1);
state = saved_state;
break;
case 'b':
case 'n':
case 'r':
case 't':
if(c == 'b') printbuf_memappend(tok->pb, "\b", 1);
else if(c == 'n') printbuf_memappend(tok->pb, "\n", 1);
else if(c == 'r') printbuf_memappend(tok->pb, "\r", 1);
else if(c == 't') printbuf_memappend(tok->pb, "\t", 1);
state = saved_state;
break;
case 'u':
tok->ucs_char = 0;
tok->st_pos = 0;
state = json_tokener_state_escape_unicode;
break;
default:
tok->err = json_tokener_error_parse_string;
goto out;
}
break;
case json_tokener_state_escape_unicode:
if(strchr(json_hex_chars, c)) {
tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4));
if(tok->st_pos == 4) {
unsigned char utf_out[3];
if (tok->ucs_char < 0x80) {
utf_out[0] = tok->ucs_char;
printbuf_memappend(tok->pb, (char*)utf_out, 1);
} else if (tok->ucs_char < 0x800) {
utf_out[0] = 0xc0 | (tok->ucs_char >> 6);
utf_out[1] = 0x80 | (tok->ucs_char & 0x3f);
printbuf_memappend(tok->pb, (char*)utf_out, 2);
} else {
utf_out[0] = 0xe0 | (tok->ucs_char >> 12);
utf_out[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
utf_out[2] = 0x80 | (tok->ucs_char & 0x3f);
printbuf_memappend(tok->pb, (char*)utf_out, 3);
}
state = saved_state;
}
} else {
tok->err = json_tokener_error_parse_string;
goto out;
}
break;
case json_tokener_state_boolean:
printbuf_memappend(tok->pb, &c, 1);
if(strncasecmp(json_true_str, tok->pb->buf,
min(tok->st_pos+1, strlen(json_true_str))) == 0) {
if(tok->st_pos == strlen(json_true_str)) {
current = json_object_new_boolean(1);
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
}
} else if(strncasecmp(json_false_str, tok->pb->buf,
min(tok->st_pos+1, strlen(json_false_str))) == 0) {
if(tok->st_pos == strlen(json_false_str)) {
current = json_object_new_boolean(0);
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
}
} else {
tok->err = json_tokener_error_parse_boolean;
goto out;
}
tok->st_pos++;
break;
case json_tokener_state_number:
if(c && strchr(json_number_chars, c)) {
printbuf_memappend(tok->pb, &c, 1);
if(c == '.' || c == 'e') tok->is_double = 1;
} else {
int numi;
double numd;
if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) {
current = json_object_new_int(numi);
} else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) {
current = json_object_new_double(numd);
} else {
tok->err = json_tokener_error_parse_number;
goto out;
}
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
}
break;
case json_tokener_state_array:
if(c == ']') {
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
} else {
if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
tok->err = json_tokener_error_depth;
goto out;
}
state = json_tokener_state_array_add;
tok->depth++;
json_tokener_reset_level(tok, tok->depth);
goto redo_char;
}
break;
case json_tokener_state_array_add:
json_object_array_add(current, obj);
saved_state = json_tokener_state_array_sep;
state = json_tokener_state_eatws;
goto redo_char;
case json_tokener_state_array_sep:
if(c == ']') {
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
} else if(c == ',') {
saved_state = json_tokener_state_array;
state = json_tokener_state_eatws;
} else {
tok->err = json_tokener_error_parse_array;
goto out;
}
break;
case json_tokener_state_object_field_start:
if(c == '}') {
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
} else if (c == '"' || c == '\'') {
tok->quote_char = c;
printbuf_reset(tok->pb);
state = json_tokener_state_object_field;
} else {
tok->err = json_tokener_error_parse_object_key_name;
goto out;
}
break;
case json_tokener_state_object_field:
if(c == tok->quote_char) {
obj_field_name = strdup(tok->pb->buf);
saved_state = json_tokener_state_object_field_end;
state = json_tokener_state_eatws;
} else if(c == '\\') {
saved_state = json_tokener_state_object_field;
state = json_tokener_state_string_escape;
} else {
printbuf_memappend(tok->pb, &c, 1);
}
break;
case json_tokener_state_object_field_end:
if(c == ':') {
saved_state = json_tokener_state_object_value;
state = json_tokener_state_eatws;
} else {
tok->err = json_tokener_error_parse_object_key_sep;
goto out;
}
break;
case json_tokener_state_object_value:
if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
tok->err = json_tokener_error_depth;
goto out;
}
state = json_tokener_state_object_value_add;
tok->depth++;
json_tokener_reset_level(tok, tok->depth);
goto redo_char;
case json_tokener_state_object_value_add:
json_object_object_add(current, obj_field_name, obj);
free(obj_field_name);
obj_field_name = NULL;
saved_state = json_tokener_state_object_sep;
state = json_tokener_state_eatws;
goto redo_char;
case json_tokener_state_object_sep:
if(c == '}') {
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
} else if(c == ',') {
saved_state = json_tokener_state_object_field_start;
state = json_tokener_state_eatws;
} else {
tok->err = json_tokener_error_parse_object_value_sep;
goto out;
}
break;
}
str++;
tok->char_offset++;
} while(c);
if(state != json_tokener_state_finish &&
saved_state != json_tokener_state_finish)
tok->err = json_tokener_error_parse_eof;
out:
if(tok->err == json_tokener_success) return json_object_get(current);
mc_debug("json_tokener_parse_ex: error %s at offset %d\n",
json_tokener_errors[tok->err], tok->char_offset);
return NULL;
}

View File

@ -0,0 +1,89 @@
/*
* $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _json_tokener_h_
#define _json_tokener_h_
#include "json_object.h"
enum json_tokener_error {
json_tokener_success,
json_tokener_continue,
json_tokener_error_depth,
json_tokener_error_parse_eof,
json_tokener_error_parse_unexpected,
json_tokener_error_parse_null,
json_tokener_error_parse_boolean,
json_tokener_error_parse_number,
json_tokener_error_parse_array,
json_tokener_error_parse_object_key_name,
json_tokener_error_parse_object_key_sep,
json_tokener_error_parse_object_value_sep,
json_tokener_error_parse_string,
json_tokener_error_parse_comment
};
enum json_tokener_state {
json_tokener_state_eatws,
json_tokener_state_start,
json_tokener_state_finish,
json_tokener_state_null,
json_tokener_state_comment_start,
json_tokener_state_comment,
json_tokener_state_comment_eol,
json_tokener_state_comment_end,
json_tokener_state_string,
json_tokener_state_string_escape,
json_tokener_state_escape_unicode,
json_tokener_state_boolean,
json_tokener_state_number,
json_tokener_state_array,
json_tokener_state_array_add,
json_tokener_state_array_sep,
json_tokener_state_object_field_start,
json_tokener_state_object_field,
json_tokener_state_object_field_end,
json_tokener_state_object_value,
json_tokener_state_object_value_add,
json_tokener_state_object_sep
};
struct json_tokener_srec
{
enum json_tokener_state state, saved_state;
struct json_object *obj;
struct json_object *current;
char *obj_field_name;
};
#define JSON_TOKENER_MAX_DEPTH 32
struct json_tokener
{
char *str;
struct printbuf *pb;
int depth, is_double, st_pos, char_offset;
enum json_tokener_error err;
unsigned int ucs_char;
char quote_char;
struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH];
};
extern const char* json_tokener_errors[];
extern struct json_tokener* json_tokener_new();
extern void json_tokener_free(struct json_tokener *tok);
extern void json_tokener_reset(struct json_tokener *tok);
extern struct json_object* json_tokener_parse(char *str);
extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
char *str, int len);
#endif

View File

@ -0,0 +1,121 @@
/*
* $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#if HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <io.h>
#endif /* defined(WIN32) */
#if !HAVE_OPEN && defined(WIN32)
# define open _open
#endif
#include "bits.h"
#include "debug.h"
#include "printbuf.h"
#include "json_object.h"
#include "json_tokener.h"
#include "json_util.h"
struct json_object* json_object_from_file(char *filename)
{
struct printbuf *pb;
struct json_object *obj;
char buf[JSON_FILE_BUF_SIZE];
int fd, ret;
if((fd = open(filename, O_RDONLY)) < 0) {
mc_error("json_object_from_file: error reading file %s: %s\n",
filename, strerror(errno));
return error_ptr(-1);
}
if(!(pb = printbuf_new())) {
mc_error("json_object_from_file: printbuf_new failed\n");
return error_ptr(-1);
}
while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
printbuf_memappend(pb, buf, ret);
}
close(fd);
if(ret < 0) {
mc_abort("json_object_from_file: error reading file %s: %s\n",
filename, strerror(errno));
printbuf_free(pb);
return error_ptr(-1);
}
obj = json_tokener_parse(pb->buf);
printbuf_free(pb);
return obj;
}
int json_object_to_file(char *filename, struct json_object *obj)
{
char *json_str;
int fd, ret;
unsigned int wpos, wsize;
if(!obj) {
mc_error("json_object_to_file: object is null\n");
return -1;
}
if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
mc_error("json_object_to_file: error opening file %s: %s\n",
filename, strerror(errno));
return -1;
}
if(!(json_str = json_object_to_json_string(obj))) { return -1; }
wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
wpos = 0;
while(wpos < wsize) {
if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
close(fd);
mc_error("json_object_to_file: error writing file %s: %s\n",
filename, strerror(errno));
return -1;
}
/* because of the above check for ret < 0, we can safely cast and add */
wpos += (unsigned int)ret;
}
close(fd);
return 0;
}

View File

@ -0,0 +1,23 @@
/*
* $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _json_util_h_
#define _json_util_h_
#include "json_object.h"
#define JSON_FILE_BUF_SIZE 4096
/* utlitiy functions */
extern struct json_object* json_object_from_file(char *filename);
extern int json_object_to_file(char *filename, struct json_object *obj);
#endif

View File

@ -0,0 +1,217 @@
/*
* $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <limits.h>
#include "linkhash.h"
void lh_abort(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vprintf(msg, ap);
exit(1);
}
unsigned long lh_ptr_hash(void *k)
{
/* CAW: refactored to be 64bit nice */
return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX);
}
int lh_ptr_equal(void *k1, void *k2)
{
return (k1 == k2);
}
unsigned long lh_char_hash(void *k)
{
unsigned int h = 0;
const char* data = k;
while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME;
return h;
}
int lh_char_equal(void *k1, void *k2)
{
return (strcmp((char*)k1, (char*)k2) == 0);
}
struct lh_table* lh_table_new(int size, char *name,
lh_entry_free_fn *free_fn,
lh_hash_fn *hash_fn,
lh_equal_fn *equal_fn)
{
int i;
struct lh_table *t;
t = calloc(1, sizeof(struct lh_table));
if(!t) lh_abort("lh_table_new: calloc failed\n");
t->count = 0;
t->size = size;
t->name = name;
t->table = calloc(size, sizeof(struct lh_entry));
if(!t->table) lh_abort("lh_table_new: calloc failed\n");
t->free_fn = free_fn;
t->hash_fn = hash_fn;
t->equal_fn = equal_fn;
for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY;
return t;
}
struct lh_table* lh_kchar_table_new(int size, char *name,
lh_entry_free_fn *free_fn)
{
return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal);
}
struct lh_table* lh_kptr_table_new(int size, char *name,
lh_entry_free_fn *free_fn)
{
return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal);
}
void lh_table_resize(struct lh_table *t, int new_size)
{
struct lh_table *new_t;
struct lh_entry *ent;
new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn);
ent = t->head;
while(ent) {
lh_table_insert(new_t, ent->k, ent->v);
ent = ent->next;
}
free(t->table);
t->table = new_t->table;
t->size = new_size;
t->head = new_t->head;
t->tail = new_t->tail;
t->resizes++;
free(new_t);
}
void lh_table_free(struct lh_table *t)
{
struct lh_entry *c;
for(c = t->head; c != NULL; c = c->next) {
if(t->free_fn) {
t->free_fn(c);
}
}
free(t->table);
free(t);
}
int lh_table_insert(struct lh_table *t, void *k, void *v)
{
unsigned long h, n;
t->inserts++;
if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2);
h = t->hash_fn(k);
n = h % t->size;
while( 1 ) {
if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break;
t->collisions++;
if(++n == t->size) n = 0;
}
t->table[n].k = k;
t->table[n].v = v;
t->count++;
if(t->head == NULL) {
t->head = t->tail = &t->table[n];
t->table[n].next = t->table[n].prev = NULL;
} else {
t->tail->next = &t->table[n];
t->table[n].prev = t->tail;
t->table[n].next = NULL;
t->tail = &t->table[n];
}
return 0;
}
struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k)
{
unsigned long h = t->hash_fn(k);
unsigned long n = h % t->size;
t->lookups++;
while( 1 ) {
if(t->table[n].k == LH_EMPTY) return NULL;
if(t->table[n].k != LH_FREED &&
t->equal_fn(t->table[n].k, k)) return &t->table[n];
if(++n == t->size) n = 0;
}
return NULL;
}
void* lh_table_lookup(struct lh_table *t, void *k)
{
struct lh_entry *e = lh_table_lookup_entry(t, k);
if(e) return e->v;
return NULL;
}
int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e)
{
ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */
/* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */
if(n < 0) { return -2; }
if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1;
t->count--;
if(t->free_fn) t->free_fn(e);
t->table[n].v = NULL;
t->table[n].k = LH_FREED;
if(t->tail == &t->table[n] && t->head == &t->table[n]) {
t->head = t->tail = NULL;
} else if (t->head == &t->table[n]) {
t->head->next->prev = NULL;
t->head = t->head->next;
} else if (t->tail == &t->table[n]) {
t->tail->prev->next = NULL;
t->tail = t->tail->prev;
} else {
t->table[n].prev->next = t->table[n].next;
t->table[n].next->prev = t->table[n].prev;
}
t->table[n].next = t->table[n].prev = NULL;
return 0;
}
int lh_table_delete(struct lh_table *t, void *k)
{
struct lh_entry *e = lh_table_lookup_entry(t, k);
if(!e) return -1;
return lh_table_delete_entry(t, e);
}

View File

@ -0,0 +1,261 @@
/*
* $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _linkhash_h_
#define _linkhash_h_
/**
* golden prime used in hash functions
*/
#define LH_PRIME 0x9e370001UL
/**
* sentinel pointer value for empty slots
*/
#define LH_EMPTY (void*)-1
/**
* sentinel pointer value for freed slots
*/
#define LH_FREED (void*)-2
struct lh_entry;
/**
* callback function prototypes
*/
typedef void (lh_entry_free_fn) (struct lh_entry *e);
/**
* callback function prototypes
*/
typedef unsigned long (lh_hash_fn) (void *k);
/**
* callback function prototypes
*/
typedef int (lh_equal_fn) (void *k1, void *k2);
/**
* An entry in the hash table
*/
struct lh_entry {
/**
* The key.
*/
void *k;
/**
* The value.
*/
void *v;
/**
* The next entry
*/
struct lh_entry *next;
/**
* The previous entry.
*/
struct lh_entry *prev;
};
/**
* The hash table structure.
*/
struct lh_table {
/**
* Size of our hash.
*/
int size;
/**
* Numbers of entries.
*/
int count;
/**
* Number of collisions.
*/
int collisions;
/**
* Number of resizes.
*/
int resizes;
/**
* Number of lookups.
*/
int lookups;
/**
* Number of inserts.
*/
int inserts;
/**
* Number of deletes.
*/
int deletes;
/**
* Name of the hash table.
*/
char *name;
/**
* The first entry.
*/
struct lh_entry *head;
/**
* The last entry.
*/
struct lh_entry *tail;
struct lh_entry *table;
/**
* A pointer onto the function responsible for freeing an entry.
*/
lh_entry_free_fn *free_fn;
lh_hash_fn *hash_fn;
lh_equal_fn *equal_fn;
};
/**
* Pre-defined hash and equality functions
*/
extern unsigned long lh_ptr_hash(void *k);
extern int lh_ptr_equal(void *k1, void *k2);
extern unsigned long lh_char_hash(void *k);
extern int lh_char_equal(void *k1, void *k2);
/**
* Convenience list iterator.
*/
#define lh_foreach(table, entry) \
for(entry = table->head; entry; entry = entry->next)
/**
* lh_foreach_safe allows calling of deletion routine while iterating.
*/
#define lh_foreach_safe(table, entry, tmp) \
for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp)
/**
* Create a new linkhash table.
* @param size initial table size. The table is automatically resized
* although this incurs a performance penalty.
* @param name the table name.
* @param free_fn callback function used to free memory for entries
* when lh_table_free or lh_table_delete is called.
* If NULL is provided, then memory for keys and values
* must be freed by the caller.
* @param hash_fn function used to hash keys. 2 standard ones are defined:
* lh_ptr_hash and lh_char_hash for hashing pointer values
* and C strings respectively.
* @param equal_fn comparison function to compare keys. 2 standard ones defined:
* lh_ptr_hash and lh_char_hash for comparing pointer values
* and C strings respectively.
* @return a pointer onto the linkhash table.
*/
extern struct lh_table* lh_table_new(int size, char *name,
lh_entry_free_fn *free_fn,
lh_hash_fn *hash_fn,
lh_equal_fn *equal_fn);
/**
* Convenience function to create a new linkhash
* table with char keys.
* @param size initial table size.
* @param name table name.
* @param free_fn callback function used to free memory for entries.
* @return a pointer onto the linkhash table.
*/
extern struct lh_table* lh_kchar_table_new(int size, char *name,
lh_entry_free_fn *free_fn);
/**
* Convenience function to create a new linkhash
* table with ptr keys.
* @param size initial table size.
* @param name table name.
* @param free_fn callback function used to free memory for entries.
* @return a pointer onto the linkhash table.
*/
extern struct lh_table* lh_kptr_table_new(int size, char *name,
lh_entry_free_fn *free_fn);
/**
* Free a linkhash table.
* If a callback free function is provided then it is called for all
* entries in the table.
* @param t table to free.
*/
extern void lh_table_free(struct lh_table *t);
/**
* Insert a record into the table.
* @param t the table to insert into.
* @param k a pointer to the key to insert.
* @param v a pointer to the value to insert.
*/
extern int lh_table_insert(struct lh_table *t, void *k, void *v);
/**
* Lookup a record into the table.
* @param t the table to lookup
* @param k a pointer to the key to lookup
* @return a pointer to the record structure of the value or NULL if it does not exist.
*/
extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k);
/**
* Lookup a record into the table
* @param t the table to lookup
* @param k a pointer to the key to lookup
* @return a pointer to the found value or NULL if it does not exist.
*/
extern void* lh_table_lookup(struct lh_table *t, void *k);
/**
* Delete a record from the table.
* If a callback free function is provided then it is called for the
* for the item being deleted.
* @param t the table to delete from.
* @param e a pointer to the entry to delete.
* @return 0 if the item was deleted.
* @return -1 if it was not found.
*/
extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e);
/**
* Delete a record from the table.
* If a callback free function is provided then it is called for the
* for the item being deleted.
* @param t the table to delete from.
* @param k a pointer to the key to delete.
* @return 0 if the item was deleted.
* @return -1 if it was not found.
*/
extern int lh_table_delete(struct lh_table *t, void *k);
#endif

View File

@ -0,0 +1,356 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2008, Eric des Courtis <eric.des.courtis@benbria.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Eric des Courtis <eric.des.courtis@benbria.com>
* Copyright (C) Benbria. All Rights Reserved.
*
* Contributor(s):
*
* Eric des Courtis <eric.des.courtis@benbria.com>
*
*
* mod_http.c -- HTTP client implementation for FreeSWITCH
*
* The purpose is to provide laguages like LUA with a _fast_ HTTP
* client implementation.
*
* Support for SSL will be provided in future versions.
* Initial release does not include win32 support.
*
*/
#include <switch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/queue.h>
#include "json.h"
#include "http_req.h"
#include "url_encoding.h"
#define HTTP_SYNTAX "<http_method> <url> <urlejson_headers> [urlejson_body]"
#define HTTP_PARAMS 4
#define HTTP_BUFFER_SIZE (256 * 1024)
/* SWITCH_STANDARD_API(http_api_main); */
#define MAX_MEMLOCS 512
#define GARBAGE_TYPES_INIT() \
typedef struct memloc{\
void *p;\
LIST_ENTRY(memloc) memlocs;\
} memloc_t
#define GARBAGE_CLEANUP() \
do{\
for(memloc_p = head.lh_first; memloc_p != NULL; \
memloc_p = memloc_p->memlocs.le_next){\
free(memloc_p->p);\
}\
}while(0)
#define GARBAGE_ADD(a) \
do {\
if(memloc_i >= MAX_MEMLOCS){\
switch_safe_free(ccmd);\
GARBAGE_CLEANUP();\
stream->write_function(stream, "-ERR\n");\
return SWITCH_STATUS_SUCCESS;\
}\
memloc_a[memloc_i].p = (void *)a;\
LIST_INSERT_HEAD(&head, memloc_a + memloc_i, memlocs);\
memloc_i++;\
}while(0)
#define GARBAGE_INIT() \
LIST_HEAD(listhead, memloc) head;\
memloc_t memloc_a[MAX_MEMLOCS];\
memloc_t *memloc_p;\
size_t memloc_i;\
LIST_INIT(&head);\
memloc_i = 0
GARBAGE_TYPES_INIT();
SWITCH_STANDARD_API(http_api_main)
{
char *ccmd;
int argc;
char *argv[HTTP_PARAMS];
char *buf;
char *method;
char *url;
char *headers_str;
char *value;
char *body;
char *body_dec;
char *t;
char *json_response;
struct json_object *json_http_headers;
char *key;
struct json_object *val;
struct lh_entry *entry;
int i;
int j;
int f;
size_t l;
size_t m;
size_t a = 0;
int ret;
http_header_t *headers;
http_request_t request;
http_response_t response;
GARBAGE_INIT();
(void)memset(&response, 0, sizeof(response));
if(cmd == NULL){
stream->write_function(stream, "-USAGE: %s\n", HTTP_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
ccmd = strdup(cmd);
argc = switch_separate_string(ccmd, ' ', argv, HTTP_PARAMS);
if(argc != HTTP_PARAMS && argc != (HTTP_PARAMS - 1)){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
return SWITCH_STATUS_SUCCESS;
}
method = argv[0];
url = argv[1];
headers_str = argv[2];
if(argc == HTTP_PARAMS){
body = argv[3];
}else{
body = (char *)malloc(1 * sizeof(char));
if(body == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
return SWITCH_STATUS_SUCCESS;
}
body[0] = '\0';
GARBAGE_ADD(body);
}
buf = (char *)malloc(HTTP_BUFFER_SIZE * sizeof(char));
if(buf == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
GARBAGE_ADD(buf);
request.version = DEFAULT_HTTP_VERSION;
l = strlen(url);
request.url = (char *)malloc((l + 1) * sizeof(char));
if(request.url == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
GARBAGE_ADD(request.url);
strcpy(request.url, url);
json_http_headers = json_tokener_parse(headers_str);
i = 0;
json_object_object_foreach(json_http_headers, key, val){
i++;
}
request.header_len = i;
headers = (http_header_t *)malloc(i * sizeof(http_header_t));
GARBAGE_ADD(headers);
i = 0;
json_object_object_foreach(json_http_headers, key, val){
l = strlen(key);
request.headers[i].field_name = (char *)malloc((l + 1) * sizeof(char));
if(request.headers[i].field_name == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
GARBAGE_ADD(request.headers[i].field_name);
strcpy(request.headers[i].field_name, key);
a += strlen(key);
value = json_object_to_json_string(val);
l = strlen(value);
request.headers[i].value = (char *)malloc((l + 1) * sizeof(char));
if(request.headers[i].value == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
GARBAGE_ADD(request.headers[i].value);
strcpy(request.headers[i].value, value);
a += strlen(value);
i++;
}
if(argc == HTTP_PARAMS){
l = strlen(body);
body_dec = url_decode(body, l);
GARBAGE_ADD(body_dec);
l = strlen(body_dec);
request.body_len = l;
request.body = body_dec;
}else request.body_len = 0;
ret = http_req(&request, &response);
if(response.version != NULL) GARBAGE_ADD(response.version);
if(response.phrase != NULL) GARBAGE_ADD(response.phrase);
if(response.headers != NULL) GARBAGE_ADD(response.headers);
if(response.body != NULL) GARBAGE_ADD(response.body);
for(i = 0; i < response.header_len; i++){
GARBAGE_ADD(response.headers[i].field_name);
GARBAGE_ADD(response.headers[i].value);
}
if(ret == ERROR){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
/* This is evil and should be changed in the future */
l = 128 + (256 * response.header_len) + (a * 2)
+ strlen("version") + strlen(response.version)
+ strlen("status_code") + 3
+ strlen("phrase") + strlen(response.phrase)
+ strlen("body") + (response.body_len * 3) + 1
+ strlen("headers")
+ 1;
/* to be safe */
l <<= 2;
json_response = (char *)malloc(l * sizeof(char));
if(json_response == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
GARBAGE_ADD(json_response);
if(response.body_len != 0){
t = (char *)malloc((response.body_len + 1) * sizeof(char));
if(t == NULL){
switch_safe_free(ccmd);
stream->write_function(stream, "-ERR\n");
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
GARBAGE_ADD(t);
(void)memcpy(t, response.body, response.body_len);
t[response.body_len] = '\0';
response.body = url_encode(t, response.body_len);
GARBAGE_ADD(response.body);
}
m = snprintf(json_response, l,
"{"
"\"version\": \"%s\","
"\"status_code\": \"%3d\","
"\"phrase\": \"%s\","
"\"body\": \"%s\","
"\"headers\": [",
response.version,
response.status_code,
response.phrase,
((response.body_len <= 0)? "":response.body)
);
for(f = HTTP_FALSE, j = 0; j < response.header_len; j++){
if(f != HTTP_FALSE){
m += snprintf(json_response + m, l - m,
","
);
}else f = HTTP_TRUE;
m += snprintf(json_response + m, l - m,
"{\"key\": \"%s\",\"value\": \"%s\"}",
response.headers[j].field_name,
response.headers[j].value
);
}
m += snprintf(json_response + m, l - m, "]}");
json_response[m] = '\0';
switch_log_printf(
SWITCH_CHANNEL_LOG,
SWITCH_LOG_NOTICE,
"RESERVED %d BYTES, USED %d BYTES, HTTP Response as JSON: %s\n",
l,
m,
json_response
);
stream->write_function(stream, "%s\n", json_response);
switch_safe_free(ccmd);
GARBAGE_CLEANUP();
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_http_load);
SWITCH_MODULE_DEFINITION(mod_http, mod_http_load, NULL, NULL);
SWITCH_MODULE_LOAD_FUNCTION(mod_http_load)
{
switch_api_interface_t *api_interface;
*module_interface =
switch_loadable_module_create_module_interface(pool, modname);
switch_log_printf(
SWITCH_CHANNEL_LOG,
SWITCH_LOG_NOTICE,
"HTTP request mod enabled\n"
);
SWITCH_ADD_API(
api_interface,
"http",
"Make HTTP requests",
http_api_main,
HTTP_SYNTAX
);
return SWITCH_STATUS_SUCCESS;
}

View File

@ -0,0 +1,144 @@
/*
* $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_STDARG_H
# include <stdarg.h>
#else /* !HAVE_STDARG_H */
# error Not enough var arg support!
#endif /* HAVE_STDARG_H */
#include "bits.h"
#include "debug.h"
#include "printbuf.h"
struct printbuf* printbuf_new()
{
struct printbuf *p;
if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL;
p->size = 32;
p->bpos = 0;
if(!(p->buf = malloc(p->size))) {
free(p);
return NULL;
}
return p;
}
int printbuf_memappend(struct printbuf *p, char *buf, int size)
{
char *t;
if(p->size - p->bpos <= size) {
int new_size = max(p->size * 2, p->bpos + size + 8);
#ifdef PRINTBUF_DEBUG
mc_debug("printbuf_memappend: realloc "
"bpos=%d wrsize=%d old_size=%d new_size=%d\n",
p->bpos, size, p->size, new_size);
#endif /* PRINTBUF_DEBUG */
if(!(t = realloc(p->buf, new_size))) return -1;
p->size = new_size;
p->buf = t;
}
memcpy(p->buf + p->bpos, buf, size);
p->bpos += size;
p->buf[p->bpos]= '\0';
return size;
}
#if !HAVE_VSNPRINTF && defined(WIN32)
# define vsnprintf _vsnprintf
#elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */
# error Need vsnprintf!
#endif /* !HAVE_VSNPRINTF && defined(WIN32) */
#if !HAVE_VASPRINTF
/* CAW: compliant version of vasprintf */
static int vasprintf(char **buf, const char *fmt, va_list ap)
{
#ifndef WIN32
static char _T_emptybuffer = '\0';
#endif /* !defined(WIN32) */
int chars;
char *b;
if(!buf) { return -1; }
#ifdef WIN32
chars = _vscprintf(fmt, ap)+1;
#else /* !defined(WIN32) */
/* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
our buffer like on some 64bit sun systems.... but hey, its time to move on */
chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;
if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */
#endif /* defined(WIN32) */
b = (char*)malloc(sizeof(char)*chars);
if(!b) { return -1; }
if((chars = vsprintf(b, fmt, ap)) < 0)
{
free(b);
} else {
*buf = b;
}
return chars;
}
#endif /* !HAVE_VASPRINTF */
int sprintbuf(struct printbuf *p, const char *msg, ...)
{
va_list ap;
char *t;
int size;
char buf[128];
/* user stack buffer first */
va_start(ap, msg);
size = vsnprintf(buf, 128, msg, ap);
va_end(ap);
/* if string is greater than stack buffer, then use dynamic string
with vasprintf. Note: some implementation of vsnprintf return -1
if output is truncated whereas some return the number of bytes that
would have been writen - this code handles both cases. */
if(size == -1 || size > 127) {
int ret;
va_start(ap, msg);
if((size = vasprintf(&t, msg, ap)) == -1) return -1;
va_end(ap);
ret = printbuf_memappend(p, t, size);
free(t);
return ret;
} else {
return printbuf_memappend(p, buf, size);
}
}
void printbuf_reset(struct printbuf *p)
{
p->buf[0] = '\0';
p->bpos = 0;
}
void printbuf_free(struct printbuf *p)
{
if(p) {
free(p->buf);
free(p);
}
}

View File

@ -0,0 +1,38 @@
/*
* $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _printbuf_h_
#define _printbuf_h_
#undef PRINTBUF_DEBUG
struct printbuf {
char *buf;
int bpos;
int size;
};
extern struct printbuf*
printbuf_new();
extern int
printbuf_memappend(struct printbuf *p, char *buf, int size);
extern int
sprintbuf(struct printbuf *p, const char *msg, ...);
extern void
printbuf_reset(struct printbuf *p);
extern void
printbuf_free(struct printbuf *p);
#endif

View File

@ -0,0 +1,125 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2008, Eric des Courtis <eric.des.courtis@benbria.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Eric des Courtis <eric.des.courtis@benbria.com>
* Copyright (C) Benbria. All Rights Reserved.
*
* Contributor(s):
*
* Eric des Courtis <eric.des.courtis@benbria.com>
*
*
* url_encoding.c -- url encoding/decoding
*
*/
#include "url_encoding.h"
#ifdef DEBUG
int main(int argc, char *argv[])
{
char *buf1;
char *buf2;
buf1 = url_encode("This is a test #$ ");
buf2 = url_decode(buf1);
printf("%s\n", buf2);
free(buf1);
free(buf2);
return EXIT_FAILURE;
}
#endif
char *url_encode(char *url, size_t l)
{
int i;
int j;
char *buf;
unsigned char c;
buf = (char *)malloc((l * 3) + 1);
if(buf == NULL){
perror("Could not allocate memory url encoding");
return NULL;
}
for(i = 0, j = 0; i < l; i++){
c = (unsigned char)url[i];
if(c <= 31 || c >= 127
|| c == '$' || c == '&' || c == '+' || c == ',' || c == '/'
|| c == ':' || c == ';' || c == '=' || c == '?' || c == '@'
|| c == ' ' || c == '"' || c == '<' || c == '>' || c == '#'
|| c == '%' || c == '{' || c == '}' || c == '|' || c == '\\'
|| c == '^' || c == '~' || c == '[' || c == ']' || c == '`'){
(void)sprintf(buf + j, "%%%X%X", c >> 4, c & 0x0F);
j += 3;
}else{
buf[j] = url[i];
j++;
}
}
buf[j] = '\0';
return buf;
}
char *url_decode(char *url, size_t l)
{
int i;
int j;
char *buf;
char c;
char d0;
char d1;
buf = (char *)malloc((l + 1) * sizeof(char));
if(buf == NULL){
perror("Could not allocate memory for decoding");
return NULL;
}
for(i = 0, j = 0; i < l; j++){
c = url[i];
if(c == '%'){
d0 = url[i + 2];
d1 = url[i + 1];
d0 = toupper(d0);
d1 = toupper(d1);
if(d0 >= 'A' && d0 <= 'F') d0 = d0 - 'A' + 10;
else if(d0 >= '0' && d0 <= '9') d0 = d0 - '0';
if(d1 >= 'A' && d1 <= 'F') d1 = d1 - 'A' + 10;
else if(d1 >= '0' && d1 <= '9') d1 = d1 - '0';
buf[j] = (d1 << 4) + d0;
i += 3;
}else{
buf[j] = url[i];
i++;
}
}
buf[j] = '\0';
return buf;
}

View File

@ -0,0 +1,42 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2008, Eric des Courtis <eric.des.courtis@benbria.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Eric des Courtis <eric.des.courtis@benbria.com>
* Copyright (C) Benbria. All Rights Reserved.
*
* Contributor(s):
*
* Eric des Courtis <eric.des.courtis@benbria.com>
*
*
* url_encoding.h -- url encoding/decoding
*
*/
#ifndef __URL_ENCODING_H__
#define __URL_ENCODING_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
char *url_encode(char *url, size_t l);
char *url_decode(char *url, size_t l);
#endif