GHashTable *http_parse_header (http_request *h, gchar *req) { GHashTable *head = g_hash_new(); gchar **lines, **items, *key, *val, *p, prefix[50]; guint i; h->method = NULL; h->uri = NULL; h->header = head; if (req == NULL) return head; lines = g_strsplit( req, "\r\n", 0 ); if (lines == NULL || lines[0] == NULL) return head; items = g_strsplit( lines[0], " ", 3 ); h->method = g_strdup( items[0] ); h->uri = g_strdup( items[1] ); // if (CONFd("Verbosity") >= 8) g_message( "http_parse_header: method_len: %d, uri_len: %d", strlen(h->method), strlen(h->uri)); if (CONFd("Verbosity") >= 8) g_message( "http_parse_header: Method: %s", h->method ); if (CONFd("Verbosity") >= 8) g_message( "http_parse_header: URI: %s", url_decode(h->uri) ); g_strfreev( items ); for (i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++ ) { key = lines[i]; val = strchr(key, ':'); if (val != NULL) { /* Separate the key from the value */ *val = '\0'; /* Normalize key -- lowercase every after 1st char */ for (p = key + 1; *p != '\0'; p++) *p = tolower(*p); /* Strip ": " plus leading and trailing space from val */ g_strchomp( val += 2 ); // ": " //if ( strcmp(key, "Referer" )== 0) { // if (CONFd("Verbosity") >= 8) g_message("http_parse_header: Referer: %s", url_decode(val) ); //} //else { if (CONFd("Verbosity") >= 8) { g_snprintf(prefix, 50, "http_parse_header: %s: ", key); syslog_message(prefix, url_decode(val), strlen(url_decode(val)) ); } g_hash_set( head, key, val ); //} } } g_strfreev( lines ); h->header = head; return head; }
GHashTable *parse_query_string( gchar *query ) { GHashTable *data = g_hash_new(); gchar **items, *key, *val, prefix[50]; guint i; if (!query) return data; items = g_strsplit( query, "&", 0 ); for ( i = 0; items[i] != NULL; i++ ) { key = items[i]; if (key == NULL) break; val = strchr( key, '=' ); if (val != NULL) *(val++) = '\0'; else val = "1"; key = url_decode( key ); val = url_decode( val ); /* Irving - fix from Yurgi - check to see if the key is already in the hash table. This deals with keys that are set twice by web sites */ if(g_hash_table_lookup_extended( data, key, NULL, NULL ) == FALSE ) { g_hash_set( data, key, val ); if(CONFd("Verbosity") >= 8) { g_snprintf(prefix, 50, "parse_query_string: %s=", key); syslog_message(prefix, val, strlen(val)); } } else if(CONFd("Verbosity") >= 8) g_message("parse_query_string: DUPLICATE key %s=%s, discarded.", key, val); g_free( key ); g_free( val ); } g_strfreev(items); return data; }
static void domark(int sig) { syslog_message(LOG_SYSLOG | LOG_INFO, "-- MARK --"); alarm(markinterval); }
void handle_parent_connection (int s) { glibtop *server = glibtop_global_server; glibtop_response _resp, *resp = &_resp; glibtop_command _cmnd, *cmnd = &_cmnd; glibtop_mountentry *mount_list; char parameter [BUFSIZ]; unsigned short device; gint64 *param_ptr; int all_fs; pid_t pid; void *ptr; glibtop_send_version (glibtop_global_server, s); if (verbose_output) syslog_message (LOG_INFO, "Parent features = %lu", glibtop_server_features); if (enable_debug) syslog_message (LOG_DEBUG, "SIZEOF: %u - %u - %u - %u - %u - %u", sizeof (glibtop_command), sizeof (glibtop_response), sizeof (glibtop_mountentry), sizeof (glibtop_union), sizeof (glibtop_sysdeps), sizeof (glibtop_response_union)); while (do_read (s, cmnd, sizeof (glibtop_command))) { if (enable_debug) syslog_message (LOG_DEBUG, "Parent (%d) received command %llu from client.", getpid (), cmnd->command); if (cmnd->data_size >= BUFSIZ) { syslog_message (LOG_WARNING, "Client sent %llu bytes, but buffer is %lu", cmnd->data_size, (unsigned long)BUFSIZ); return; } memset (resp, 0, sizeof (glibtop_response)); memset (parameter, 0, sizeof (parameter)); if (cmnd->data_size) { if (enable_debug) syslog_message (LOG_DEBUG, "Client has %llu bytes of data.", cmnd->data_size); do_read (s, parameter, cmnd->data_size); } else if (cmnd->size) { memcpy (parameter, cmnd->parameter, cmnd->size); } switch (cmnd->command) { case GLIBTOP_CMND_QUIT: do_output (s, resp, 0, 0, NULL); return; case GLIBTOP_CMND_SYSDEPS: memcpy (&resp->u.sysdeps, &server->sysdeps, sizeof (glibtop_sysdeps)); resp->u.sysdeps.features = GLIBTOP_SYSDEPS_ALL; do_output (s, resp, _offset_union (sysdeps), 0, NULL); break; case GLIBTOP_CMND_CPU: glibtop_get_cpu_l (server, &resp->u.data.cpu); do_output (s, resp, _offset_data (cpu), 0, NULL); break; case GLIBTOP_CMND_MEM: glibtop_get_mem_l (server, &resp->u.data.mem); do_output (s, resp, _offset_data (mem), 0, NULL); break; case GLIBTOP_CMND_SWAP: glibtop_get_swap_l (server, &resp->u.data.swap); do_output (s, resp, _offset_data (swap), 0, NULL); break; case GLIBTOP_CMND_UPTIME: glibtop_get_uptime_l (server, &resp->u.data.uptime); do_output (s, resp, _offset_data (uptime), 0, NULL); break; case GLIBTOP_CMND_LOADAVG: glibtop_get_loadavg_l (server, &resp->u.data.loadavg); do_output (s, resp, _offset_data (loadavg), 0, NULL); break; case GLIBTOP_CMND_SHM_LIMITS: glibtop_get_shm_limits_l (server, &resp->u.data.shm_limits); do_output (s, resp, _offset_data (shm_limits), 0, NULL); break; case GLIBTOP_CMND_MSG_LIMITS: glibtop_get_msg_limits_l (server, &resp->u.data.msg_limits); do_output (s, resp, _offset_data (msg_limits), 0, NULL); break; case GLIBTOP_CMND_SEM_LIMITS: glibtop_get_sem_limits_l (server, &resp->u.data.sem_limits); do_output (s, resp, _offset_data (sem_limits), 0, NULL); break; case GLIBTOP_CMND_PROCLIST: param_ptr = (gint64 *) parameter; ptr = glibtop_get_proclist_l (server, &resp->u.data.proclist, param_ptr [0], param_ptr [1]); do_output (s, resp, _offset_data (proclist), resp->u.data.proclist.total, ptr); g_free (ptr); break; case GLIBTOP_CMND_PROC_MAP: memcpy (&pid, parameter, sizeof (pid_t)); ptr = glibtop_get_proc_map_l (server, &resp->u.data.proc_map, pid); do_output (s, resp, _offset_data (proc_map), resp->u.data.proc_map.total, ptr); g_free (ptr); break; case GLIBTOP_CMND_PROC_WD: /* FIXME */ break; case GLIBTOP_CMND_NETLIST: /* FIXME */ break; case GLIBTOP_CMND_PROC_ARGS: memcpy (&pid, parameter, sizeof (pid_t)); ptr = glibtop_get_proc_args_l (server, &resp->u.data.proc_args, pid, 0); do_output (s, resp, _offset_data (proc_args), ptr ? resp->u.data.proc_args.size+1 : 0, ptr); g_free (ptr); break; case GLIBTOP_CMND_PROC_STATE: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_state_l (server, &resp->u.data.proc_state, pid); do_output (s, resp, _offset_data (proc_state), 0, NULL); break; case GLIBTOP_CMND_PROC_UID: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_uid_l (server, &resp->u.data.proc_uid, pid); do_output (s, resp, _offset_data (proc_uid), 0, NULL); break; case GLIBTOP_CMND_PROC_MEM: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_mem_l (server, &resp->u.data.proc_mem, pid); do_output (s, resp, _offset_data (proc_mem), 0, NULL); break; case GLIBTOP_CMND_PROC_TIME: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_time_l (server, &resp->u.data.proc_time, pid); do_output (s, resp, _offset_data (proc_time), 0, NULL); break; case GLIBTOP_CMND_PROC_SIGNAL: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_signal_l (server, &resp->u.data.proc_signal, pid); do_output (s, resp, _offset_data (proc_signal), 0, NULL); break; case GLIBTOP_CMND_PROC_KERNEL: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_kernel_l (server, &resp->u.data.proc_kernel, pid); do_output (s, resp, _offset_data (proc_kernel), 0, NULL); break; case GLIBTOP_CMND_PROC_SEGMENT: memcpy (&pid, parameter, sizeof (pid_t)); glibtop_get_proc_segment_l (server, &resp->u.data.proc_segment, pid); do_output (s, resp, _offset_data (proc_segment), 0, NULL); break; case GLIBTOP_CMND_MOUNTLIST: memcpy (&all_fs, parameter, sizeof (all_fs)); mount_list = glibtop_get_mountlist_l (server, &resp->u.data.mountlist, all_fs); do_output (s, resp, _offset_data (mountlist), resp->u.data.mountlist.total, mount_list); g_free (mount_list); break; case GLIBTOP_CMND_FSUSAGE: glibtop_get_fsusage_l (server, &resp->u.data.fsusage, parameter); do_output (s, resp, _offset_data (fsusage), 0, NULL); break; case GLIBTOP_CMND_PPP: memcpy (&device, parameter, sizeof (device)); glibtop_get_ppp_l (server, &resp->u.data.ppp, device); do_output (s, resp, _offset_data (ppp), 0, NULL); break; case GLIBTOP_CMND_NETLOAD: glibtop_get_netload_l (server, &resp->u.data.netload, parameter); do_output (s, resp, _offset_data (netload), 0, NULL); break; default: syslog_message (LOG_ERR, "Parent received unknown command %llu.", cmnd->command); break; } } }
guint http_request_read (http_request *h) { gchar *buf = g_new( gchar, BUFSIZ + 1 ); /* GIOStatus r; GError *err = NULL; */ GIOError r; guint s, times, n = 0, t = 0; gchar *c_len_hdr = NULL; guint hdr_len = 0, c_len = 0, tot_req_size = 0; struct timeval tv; fd_set fdset; FD_ZERO(&fdset); FD_SET(g_io_channel_unix_get_fd(h->sock), &fdset); tv.tv_sec = 0; buf[0] = '\0'; buf[BUFSIZ] = '\0'; // for (t = 0, n = BUF_SIZ; n == BUF_SIZ && // h->buffer->len < MAX_REQUEST_SIZE; t += n ) { // BPsmythe: The above (original) loop will never execute // more than once unless the size of the buffer read in (n) // is equal to the constant BUF_SIZE. What is desired is // to keep looping until there is nothing left to read. // The for was changed to look for the end of the headers. // FIXME: We should use the newer g_io_channel_read_char // // TJaqua: Added buffer overflow checking, content read loop from 0.93pre2, and fixed up the timeouts, logging and error exits if (CONFd("Verbosity") >= 7) g_message("http_request_read: READING request from peer %s (on %s, fd: %d)", h->peer_ip, h->sock_ip, g_io_channel_unix_get_fd(h->sock)); if (CONFd("Verbosity") >= 9) g_message("http_request_read: entering HEADER read loop (BUFSIZE=%u)", BUFSIZ); for (times=MAX_REQ_TIMEOUTS; !hdr_len && (times > 0); t += n ) { n=0; /* r = g_io_channel_read_chars( h->sock, buf, BUFSIZ, &n, &err ); if (r == G_IO_STATUS_ERROR || err != NULL) { g_message( "http_request_read: Socket IO ERROR: %s, exiting!", err->message ); g_error_free(err); */ r = g_io_channel_read( h->sock, buf, BUFSIZ, &n); if (r != G_IO_ERROR_NONE) { g_warning( "http_request_read: Socket IO ERROR: %m, exiting!" ); g_free(buf); return 0; } if (CONFd("Verbosity") >= 9) g_message("http_request_read: HEADER loop read %u bytes", n); buf[n] = '\0'; if (n && CONFd("Verbosity") >= 11) syslog_message("RAW_HDR_BUF: ", buf, n); if(strlen(buf) < n-1) g_warning("http_request_read: Trailing data past string in buffer was DICARDED!"); if (h->buffer->len == MAX_REQUEST_SIZE) g_warning("http_request_read: header buffer full (%u bytes, %u bytes discarded!)", MAX_REQUEST_SIZE, n); else if (n <= (MAX_REQUEST_SIZE - h->buffer->len)) { if(CONFd("Verbosity") >= 11) g_message("http_request_read: APPENDING buffer to HEADER."); if(n) g_string_append(h->buffer, buf); else if (CONFd("Verbosity") >= 6) g_message("http_request_read: No data in buffer."); //if(CONFd("Verbosity") >= 11) g_message("http_request_read: Partial HEADER (%u bytes) is: %s", h->buffer->len, h->buffer->str); } else { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: header buffer full (%u bytes, %u bytes discarded!)", MAX_REQUEST_SIZE, n - (MAX_REQUEST_SIZE - h->buffer->len)); buf[MAX_REQUEST_SIZE - h->buffer->len] = '\0'; g_string_append(h->buffer, buf); } times--; // BPsmythe: Check for the end of the headers. if (hdr_len = http_get_hdr_len(h->buffer->str)) { if (CONFd("Verbosity") >= 6) g_message("http_request_read: HEADER END found, length: %u", hdr_len ); } else { if(!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: HEADER END not found after %d tries, exiting!", MAX_REQ_TIMEOUTS); if (!t) g_message("http_request_read: Empty HTTP-request header."); else g_message("http_request_read: Invalid HTTP-request header, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); return 0; } if(CONFd("Verbosity") >= 11) g_message("http_request_read: Waiting for next I/O on socket, (%d more tries).", times); tv.tv_usec = REQ_TIMEOUT; while(times && !(s = select (g_io_channel_unix_get_fd(h->sock)+1, &fdset, NULL, NULL, &tv))) { times--; if (CONFd("Verbosity") >= 7) g_message("http_request_read: HEADER select timeout, %d more tries", times); tv.tv_usec = REQ_TIMEOUT; } if(s<0) { g_warning("http_request_read: ERROR in select, exiting!"); g_free(buf); return 0; } else if(!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: Too many TIMEOUTS waiting for HEADER end!"); if (!t) g_message("http_request_read: Empty HTTP-request header."); else g_message("http_request_read: Invalid HTTP-request header, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); return 0; } else if(CONFd("Verbosity") >= 11) g_message("http_request_read: Recieved I/O on socket."); } } if (CONFd("Verbosity") >= 10) syslog_message("RAW_HEADER: ", h->buffer->str, h->buffer->len); // Read the content length from the header http_parse_header( h, h->buffer->str ); if( (HEADER("Content-length")) && (c_len = atoi(HEADER("Content-length"))) ) { if (CONFd("Verbosity") >= 9) g_message("http_request_read: entering CONTENT read loop to read %u bytes.", c_len); tot_req_size = hdr_len + c_len; for (times=MAX_REQ_TIMEOUTS; (t < tot_req_size) && (times > 0); t += n ) { if (CONFd("Verbosity") >= 9) g_message("http_request_read: %u bytes of %u total.", t, tot_req_size ); n=0; /* r = g_io_channel_read_chars( h->sock, buf, BUFSIZ, &n, &err ); if (r == G_IO_STATUS_ERROR || err != NULL) { g_message( "http_request_read: Socket-IO ERROR: %s, exiting!", err->message ); g_error_free(err); */ r = g_io_channel_read( h->sock, buf, BUFSIZ, &n); if (r != G_IO_ERROR_NONE) { g_warning( "http_request_read: Socket-IO ERROR: %m, exiting!" ); g_free(buf); return 0; } if (CONFd("Verbosity") >= 9) g_message("http_request_read: CONTENT loop read %d bytes", n ); buf[n] = '\0'; if (n && CONFd("Verbosity") >= 11) syslog_message("RAW_CON_BUF: ", buf, n); if (h->buffer->len == MAX_REQUEST_SIZE) { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Maximum request length EXCEEDED (%u bytes discarded! Continuing to read out content.)", n); } else if (h->buffer->len == tot_req_size) { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Content length EXCEEDED (%u bytes discarded! Shouldn't happen!)", n); } else if (h->buffer->len + n >= MAX_REQUEST_SIZE) { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Max buffer length EXCEEDED (%u bytes discarded! Continuing to read out content.)", n - (MAX_REQUEST_SIZE - h->buffer->len)); buf[MAX_REQUEST_SIZE - h->buffer->len] = '\0'; g_string_append(h->buffer, buf); } else if (n <= (tot_req_size - h->buffer->len)) { if(CONFd("Verbosity") >= 11) g_message("http_request_read: APPENDING buffer to CONTENT."); if(n) g_string_append(h->buffer, buf); else if (CONFd("Verbosity") >= 6) g_message("http_request_read: No data in buffer."); } else { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Content length EXCEEDED (%u bytes added, %u bytes discarded!)", tot_req_size - h->buffer->len, n - (tot_req_size - h->buffer->len)); buf[tot_req_size - h->buffer->len] = '\0'; g_string_append(h->buffer, buf); } times--; // TJaqua: Check for the end of the content. if ((t+n) >= tot_req_size) { if (CONFd("Verbosity") >= 6) g_message("http_request_read: CONTENT end reached, length: %u", tot_req_size); } else { if (!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: CONTENT END not found after %d tries, exiting!", MAX_REQ_TIMEOUTS); if (t == hdr_len) g_message("http_request_read: Empty CONTENT, socket may have stalled."); else g_message("http_request_read: CONTENT unfinished, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); //We still got the header, though, so return it. g_string_truncate(h->buffer, hdr_len); return hdr_len; } if(CONFd("Verbosity") >= 11) g_message("http_request_read: Waiting for next I/O on socket."); tv.tv_usec = REQ_TIMEOUT; while (times && !(s = select (g_io_channel_unix_get_fd(h->sock)+1, &fdset, NULL, NULL, &tv))) { times--; if (CONFd("Verbosity") >= 7) g_message("http_request_read: CONTENT select timeout, %d more tries", times); tv.tv_usec = REQ_TIMEOUT; } if(s<0) { g_warning("http_request_read: ERROR in select, exiting!"); g_free(buf); //We still got the header, though, so return it. g_string_truncate(h->buffer, hdr_len); return hdr_len; } else if (!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: Too many TIMEOUTS waiting for CONTENT end!"); if (t == hdr_len) g_message("http_request_read: Empty CONTENT, socket may have stalled."); else g_message("http_request_read: Invalid HTTP-request header, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); //We still got the header, though, so return it. g_string_truncate(h->buffer, hdr_len); return hdr_len; } else if (CONFd("Verbosity") >= 11) g_message("http_request_read: Received I/O on socket."); } } if (CONFd("Verbosity") >= 10) syslog_message("RAW_CONTENT: ", &(h->buffer->str[hdr_len]), h->buffer->len - hdr_len); if (t<tot_req_size) g_message("http_request_read: CONTENT unfinished - should not happen!"); } if (CONFd("Verbosity") >= 6) g_message("http_request_read: FINISHED read (%u bytes total), exiting.", t); g_free(buf); return t; }