static int scan_identifier(void) { struct buffer buf; /* for the first char, no numbers are allowed */ if(isalpha(*src) || *src == '_') { buffer_init(&buf); buffer_add_char(&buf, *src); } else return 0; ++yylloc.last_column; ++src; while(IDENTIFIER_CHAR(*src)) { buffer_add_char(&buf, *src); ++yylloc.last_column; ++src; } buffer_add_char(&buf, 0); yylval.identifier = buf.data; #ifdef DEBUG printf("yylex returns identifier %s\n", yylval.identifier); #endif return IDENTIFIER; }
/* Internal function to read until the end of identifier, checking if it is a keyword. */ static inline void lexer_read_id (struct lexer *lex, struct token *tok, char **buf, size_t *size, char c) { char *index = *buf; size_t search; do { buffer_add_char (buf, &index, size, c); c = lexer_getch (lex); } while (isalnum (c) || c == '_'); lexer_ungetch (lex, c); buffer_add_char (buf, &index, size, 0); search = kw_bsearch (*buf, keywords, keywords_length); if (search != keywords_length) { if (*buf) free (*buf); *size = 0; *buf = NULL; tval_tok_init (tok, tok_keyword, (enum token_kind)(search + tv_function)); return; } tok->tok_class = tok_id; return; }
static int scan_string(void) { char new_char; struct buffer buf; if(*src != '"') return 0; buffer_init(&buf); ++yylloc.last_column; ++src; while(*src != '"') { if(*src == 0) { string_does_not_end: location_error(yylloc, "String does not end"); } if(*src == '\\') { ++yylloc.last_column; ++src; if(*src == 0) goto string_does_not_end; if(*src == '\n') { /* backslash newline means ignore newline */ ++yylloc.last_line; yylloc.last_column = 1; ++src; continue; } new_char = slash_char(*src); } else new_char = *src; buffer_add_char(&buf, new_char); if(*src == '\n') { ++yylloc.last_line; yylloc.last_column = 1; } else ++yylloc.last_column; ++src; } buffer_add_char(&buf, 0); yylval.string = buf.data; #ifdef DEBUG printf("yylex returns \"%s\"\n", yylval.string); #endif ++yylloc.last_column; ++src; /* now src points to the char after the " */ return STRING; }
/** @brief Add a message to an output buffer. @param outbuf Pointer to the output buffer. @param msg Pointer to the message to be added, in the form of a JSON string. Since the output buffer is in the form of a JSON array, prepend a left bracket to the first message, and a comma to subsequent ones. Used only by servers to respond to clients. */ static inline void append_msg( growing_buffer* outbuf, const char* msg ) { if( outbuf && msg ) { char prefix = buffer_length( outbuf ) > 0 ? ',' : '['; buffer_add_char( outbuf, prefix ); buffer_add( outbuf, msg ); } }
void net_connect(net *n, buffer *b, int c) { b->size = 0; buffer_add_string(b, "s="); buffer_add_string(b, n->session); buffer_add_char(b, 0); net_post(n, c, b, "https://webchat.freenode.net/dynamic/test/e/s", b->data); }
void buffer_add_cchar(buffer *b, int c) { char t[32]; if (isunreserved(c)) buffer_add_char(b, c); else { sprintf(t, "%%%02X", (unsigned char)c); buffer_add_string(b, t); } }
/* Function to read a hex number */ static inline void lexer_read_octal_number (struct lexer *lex, struct token *tok, char **buf, size_t * size, char c) { char *index = *buf; assert (c == '0', "a character must be '0'"); buffer_add_char (buf, &index, size, c); do { buffer_add_char (buf, &index, size, c); c = lexer_getch (lex); } while (c >= '0' && c < '8'); lexer_ungetch (lex, c); buffer_add_char (buf, &index, size, 0); tok->tok_class = tok_octnum; tok->uses_buf = true; }
/* Internal function to read until the end of comment. */ static inline enum token_class lexer_read_comments (struct lexer *lex, char **buf, size_t * size) { char *index = *buf; while (true) { char c = lexer_getch (lex); if (c == EOF) break; if (c == '\n') break; buffer_add_char (buf, &index, size, c); } buffer_add_char (buf, &index, size, '\0'); return tok_comments; }
/* Function to read a hex number */ static inline void lexer_read_hex_number (struct lexer *lex, struct token *tok, char **buf, size_t * size, char c) { char *index = *buf; assert (c == '0', "a character must be '0', '%c' found", c); buffer_add_char (buf, &index, size, c); c = lexer_getch (lex); assert (c == 'x' || c == 'X', "a character must be 'x' or 'X', '%c' found", c); do { buffer_add_char (buf, &index, size, c); c = lexer_getch (lex); } while (isxdigit (c)); lexer_ungetch (lex, c); buffer_add_char (buf, &index, size, 0); tok->tok_class = tok_hexnum; tok->uses_buf = true; }
void buffer_add_cstring(buffer *b, const char *c) { char t[32]; while (*c) { if (isunreserved(*c)) buffer_add_char(b, *c); else { sprintf(t, "%%%02X", (unsigned char)*c); buffer_add_string(b, t); } c++; } }
static char* _escape_xml (const char* text) { growing_buffer* b = buffer_init(256); int len = strlen(text); int i; for (i = 0; i < len; i++) { if (text[i] == '&') buffer_add(b,"&"); else if (text[i] == '<') buffer_add(b,"<"); else if (text[i] == '>') buffer_add(b,">"); else buffer_add_char(b,text[i]); } return buffer_release(b); }
/** @brief Send any response messages that have accumulated in the output buffer. @param ses Pointer to the current application session. @param outbuf Pointer to the output buffer. @return Zero if successful, or -1 if not. Used only by servers to respond to clients. */ static int flush_responses( osrfAppSession* ses, growing_buffer* outbuf ) { // Collect any inbound traffic on the socket(s). This doesn't accomplish anything for the // immediate task at hand, but it may help to keep TCP from getting clogged in some cases. osrf_app_session_queue_wait( ses, 0, NULL ); int rc = 0; if( buffer_length( outbuf ) > 0 ) { // If there's anything to send... buffer_add_char( outbuf, ']' ); // Close the JSON array if( osrfSendTransportPayload( ses, OSRF_BUFFER_C_STR( ses->outbuf ))) { osrfLogError( OSRF_LOG_MARK, "Unable to flush response buffer" ); rc = -1; } } buffer_reset( ses->outbuf ); return rc; }
/* Internal function to read until the end of string/char ignoring escape sequences. */ static inline enum token_class lexer_read_string (struct lexer *lex, char **buf, size_t * size, char c) { char *index = *buf; const char stop = c; assert (stop == '"', "inapproriate starting symbol for string or char"); buffer_add_char (buf, &index, size, stop); while (true) { c = lexer_getch (lex); if (c == EOF) { if (lex->error_notifications) error_loc (lex->loc, "unexpected end of file in the middle of string"); buffer_add_char (buf, &index, size, 0); return tok_unknown; } buffer_add_char (buf, &index, size, c); if (c == '\\') { char cc = lexer_getch (lex); if (cc == EOF) { if (lex->error_notifications) error_loc (lex->loc, "unexpected end of file in the middle of string"); buffer_add_char (buf, &index, size, 0); return tok_unknown; } buffer_add_char (buf, &index, size, cc); } else if (c == stop) break; } buffer_add_char (buf, &index, size, 0); return tok_string; }
/* Internal function to read until the end of number. */ static inline enum token_class lexer_read_number (struct lexer *lex, char **buf, size_t * size, char c) { bool isreal = false; bool saw_dot = false; bool saw_exp = false; char *index = *buf; buffer_add_char (buf, &index, size, c); if (c == '.') { isreal = true; saw_dot = true; c = lexer_getch (lex); if (!isdigit (c)) { if (lex->error_notifications) error_loc (lex->loc, "digit expected, '%c' found instead", c); lexer_ungetch (lex, c); goto return_unknown; } else buffer_add_char (buf, &index, size, c); } while (true) { c = lexer_getch (lex); if (c == EOF) { if (lex->error_notifications) error_loc (lex->loc, "unexpected end of file"); goto return_unknown; } else if (c == 'e' || c == 'E') { if (saw_exp) { if (lex->error_notifications) error_loc (lex->loc, "exponent is specified more than once"); goto return_unknown; } isreal = true; buffer_add_char (buf, &index, size, c); c = lexer_getch (lex); if (c == '+' || c == '-') { buffer_add_char (buf, &index, size, c); c = lexer_getch (lex); } if (!isdigit (c)) { if (lex->error_notifications) error_loc (lex->loc, "digit expected after exponent sign"); goto return_unknown; } else buffer_add_char (buf, &index, size, c); while (isdigit (c = lexer_getch (lex))) buffer_add_char (buf, &index, size, c); break; } else if (c == '.') { if (saw_dot) { if (lex->error_notifications) error_loc (lex->loc, "more than one dot in the number "); goto return_unknown; } saw_dot = true; isreal = true; } else if (!isdigit (c)) break; buffer_add_char (buf, &index, size, c); } lexer_ungetch (lex, c); buffer_add_char (buf, &index, size, 0); if (isreal) return tok_realnum; else return tok_intnum; return_unknown: buffer_add_char (buf, &index, size, 0); return tok_unknown; }
void buffer_add_string(buffer *b, const char *c) { while (*c) { buffer_add_char(b, *c); c++; } }
static int osrf_json_gateway_method_handler (request_rec *r) { /* make sure we're needed first thing*/ if (strcmp(r->handler, MODULE_NAME )) return DECLINED; osrf_json_gateway_dir_config* dir_conf = ap_get_module_config(r->per_dir_config, &osrf_json_gateway_module); /* provide 2 different JSON parsers and serializers to support legacy JSON */ jsonObject* (*parseJSONFunc) (const char*) = legacy_jsonParseString; char* (*jsonToStringFunc) (const jsonObject*) = legacy_jsonObjectToJSON; if(dir_conf->legacyJSON) { ap_log_rerror( APLOG_MARK, APLOG_DEBUG, 0, r, "Using legacy JSON"); } else { parseJSONFunc = jsonParse; jsonToStringFunc = jsonObjectToJSON; } osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: entered request handler"); /* verify we are connected */ if( !bootstrapped || !osrfSystemGetTransportClient()) { ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, r, "Cannot process request " "because the OpenSRF JSON gateway has not been bootstrapped..."); usleep( 100000 ); /* 100 milliseconds */ exit(1); } osrfLogSetAppname("osrf_json_gw"); char* osrf_locale = NULL; char* param_locale = NULL; /* locale for this call */ char* service = NULL; /* service to connect to */ char* method = NULL; /* method to perform */ char* format = NULL; /* method to perform */ char* a_l = NULL; /* request api level */ char* input_format = NULL; /* POST data format, defaults to 'format' */ int isXML = 0; int api_level = 1; r->allowed |= (AP_METHOD_BIT << M_GET); r->allowed |= (AP_METHOD_BIT << M_POST); osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: parsing URL params"); osrfStringArray* mparams = NULL; osrfStringArray* params = apacheParseParms(r); /* free me */ param_locale = apacheGetFirstParamValue( params, "locale" ); service = apacheGetFirstParamValue( params, "service" ); method = apacheGetFirstParamValue( params, "method" ); format = apacheGetFirstParamValue( params, "format" ); input_format = apacheGetFirstParamValue( params, "input_format" ); a_l = apacheGetFirstParamValue( params, "api_level" ); mparams = apacheGetParamValues( params, "param" ); /* free me */ if(format == NULL) format = strdup( "json" ); if(input_format == NULL) input_format = strdup( format ); /* set the user defined timeout value */ int timeout = 60; char* tout = apacheGetFirstParamValue( params, "timeout" ); /* request timeout in seconds */ if( tout ) { timeout = atoi(tout); osrfLogDebug(OSRF_LOG_MARK, "Client supplied timeout of %d", timeout); free( tout ); } if (a_l) { api_level = atoi(a_l); free( a_l ); } if (!strcasecmp(format, "xml")) { isXML = 1; ap_set_content_type(r, "application/xml"); } else { ap_set_content_type(r, "text/plain"); } free( format ); int ret = OK; /* ----------------------------------------------------------------- */ /* Grab the requested locale using the Accept-Language header*/ if ( !param_locale ) { if ( apr_table_get(r->headers_in, "X-OpenSRF-Language") ) { param_locale = strdup( apr_table_get(r->headers_in, "X-OpenSRF-Language") ); } else if ( apr_table_get(r->headers_in, "Accept-Language") ) { param_locale = strdup( apr_table_get(r->headers_in, "Accept-Language") ); } } if (param_locale) { growing_buffer* osrf_locale_buf = buffer_init(16); if (index(param_locale, ',')) { int ind = index(param_locale, ',') - param_locale; int i; for ( i = 0; i < ind && i < 128; i++ ) buffer_add_char( osrf_locale_buf, param_locale[i] ); } else { buffer_add( osrf_locale_buf, param_locale ); } free(param_locale); osrf_locale = buffer_release( osrf_locale_buf ); } else { osrf_locale = strdup( osrf_json_default_locale ); } /* ----------------------------------------------------------------- */ if(!(service && method)) { osrfLogError(OSRF_LOG_MARK, "Service [%s] not found or not allowed", service); ret = HTTP_NOT_FOUND; } else { /* This will log all heaers to the apache error log const apr_array_header_t* arr = apr_table_elts(r->headers_in); const void* ptr; while( (ptr = apr_array_pop(arr)) ) { apr_table_entry_t* e = (apr_table_entry_t*) ptr; fprintf(stderr, "Table entry: %s : %s\n", e->key, e->val ); } fflush(stderr); */ osrfAppSession* session = osrfAppSessionClientInit(service); osrf_app_session_set_locale(session, osrf_locale); double starttime = get_timestamp_millis(); int req_id = -1; if(!strcasecmp(input_format, "json")) { jsonObject * arr = jsonNewObject(NULL); const char* str; int i = 0; while( (str = osrfStringArrayGetString(mparams, i++)) ) jsonObjectPush(arr, parseJSONFunc(str)); req_id = osrfAppSessionSendRequest( session, arr, method, api_level ); jsonObjectFree(arr); } else { /** * If we receive XML method params, convert each param to a JSON object * and pass the array of JSON object params to the method */ if(!strcasecmp(input_format, "xml")) { jsonObject* jsonParams = jsonNewObject(NULL); const char* str; int i = 0; while( (str = osrfStringArrayGetString(mparams, i++)) ) { jsonObjectPush(jsonParams, jsonXMLToJSONObject(str)); } req_id = osrfAppSessionSendRequest( session, jsonParams, method, api_level ); jsonObjectFree(jsonParams); } } if( req_id == -1 ) { osrfLogError(OSRF_LOG_MARK, "I am unable to communicate with opensrf..going away..."); osrfAppSessionFree(session); /* we don't want to spawn an intense re-forking storm * if there is no jabber server.. so give it some time before we die */ usleep( 100000 ); /* 100 milliseconds */ exit(1); } /* ----------------------------------------------------------------- */ /* log all requests to the activity log */ const char* authtoken = apr_table_get(r->headers_in, "X-OILS-Authtoken"); if(!authtoken) authtoken = ""; growing_buffer* act = buffer_init(128); buffer_fadd(act, "[%s] [%s] [%s] %s %s", r->connection->remote_ip, authtoken, osrf_locale, service, method ); const char* str; int i = 0; while( (str = osrfStringArrayGetString(mparams, i++)) ) { if( i == 1 ) { OSRF_BUFFER_ADD(act, " "); OSRF_BUFFER_ADD(act, str); } else { OSRF_BUFFER_ADD(act, ", "); OSRF_BUFFER_ADD(act, str); } } osrfLogActivity( OSRF_LOG_MARK, act->buf ); buffer_free(act); /* ----------------------------------------------------------------- */ osrfMessage* omsg = NULL; int statuscode = 200; /* kick off the object */ if (isXML) ap_rputs( "<response xmlns=\"http://opensrf.org/-/namespaces/gateway/v1\"><payload>", r ); else ap_rputs("{\"payload\":[", r); int morethan1 = 0; char* statusname = NULL; char* statustext = NULL; char* output = NULL; while((omsg = osrfAppSessionRequestRecv( session, req_id, timeout ))) { statuscode = omsg->status_code; const jsonObject* res; if( ( res = osrfMessageGetResult(omsg)) ) { if (isXML) { output = jsonObjectToXML( res ); } else { output = jsonToStringFunc( res ); if( morethan1 ) ap_rputs(",", r); /* comma between JSON array items */ } ap_rputs(output, r); free(output); morethan1 = 1; } else { if( statuscode > 299 ) { /* the request returned a low level error */ statusname = omsg->status_name ? strdup(omsg->status_name) : strdup("Unknown Error"); statustext = omsg->status_text ? strdup(omsg->status_text) : strdup("No Error Message"); osrfLogError( OSRF_LOG_MARK, "Gateway received error: %s", statustext ); } } osrfMessageFree(omsg); if(statusname) break; } double duration = get_timestamp_millis() - starttime; osrfLogDebug(OSRF_LOG_MARK, "gateway request took %f seconds", duration); if (isXML) ap_rputs("</payload>", r); else ap_rputs("]",r); /* finish off the payload array */ if(statusname) { /* add a debug field if the request died */ ap_log_rerror( APLOG_MARK, APLOG_INFO, 0, r, "OpenSRF JSON Request returned error: %s -> %s", statusname, statustext ); int l = strlen(statusname) + strlen(statustext) + 32; char buf[l]; if (isXML) snprintf( buf, sizeof(buf), "<debug>\"%s : %s\"</debug>", statusname, statustext ); else { char bb[l]; snprintf(bb, sizeof(bb), "%s : %s", statusname, statustext); jsonObject* tmp = jsonNewObject(bb); char* j = jsonToStringFunc(tmp); snprintf( buf, sizeof(buf), ",\"debug\": %s", j); free(j); jsonObjectFree(tmp); } ap_rputs(buf, r); free(statusname); free(statustext); } /* insert the status code */ char buf[32]; if (isXML) snprintf(buf, sizeof(buf), "<status>%d</status>", statuscode ); else snprintf(buf, sizeof(buf), ",\"status\":%d", statuscode ); ap_rputs( buf, r ); if (isXML) ap_rputs("</response>", r); else ap_rputs( "}", r ); /* finish off the object */ osrfAppSessionFree(session); } osrfLogInfo(OSRF_LOG_MARK, "Completed processing service=%s, method=%s", service, method); osrfStringArrayFree(params); osrfStringArrayFree(mparams); free( osrf_locale ); free( input_format ); free( method ); free( service ); osrfLogDebug(OSRF_LOG_MARK, "Gateway served %d requests", ++numserved); osrfLogClearXid(); return ret; }