1 /*
2 
3   ----------------------------------------------------
4   httpry - HTTP logging and information retrieval tool
5   ----------------------------------------------------
6 
7   Copyright (c) 2005-2014 Jason Bittel <jason.bittel@gmail.com>
8 
9 */
10 
11 /*
12   The methods data structure is an unbalanced binary tree. All
13   packets are checked to see if they have a method contained
14   here; any packets that do not will be ignored.
15 
16   This doesn't use a hash because the length of the potential
17   method is not known. At this point in the main processing
18   loop the packet data is still in a static buffer, so this
19   gives us a simpler solution. Perhaps at some point the flow
20   of the packet processing will be changed and we can switch
21   to a more traditional lookup table approach.
22 */
23 
24 #include <ctype.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include "error.h"
29 #include "methods.h"
30 #include "utility.h"
31 
32 typedef struct method_node METHOD_NODE;
33 struct method_node {
34         char *method;
35         METHOD_NODE *left, *right;
36 };
37 
38 static METHOD_NODE *methods = NULL;
39 
40 int insert_method(char *str, size_t len);
41 void free_node(METHOD_NODE *node);
42 
43 /* Parse and insert methods from methods string */
parse_methods_string(char * str)44 void parse_methods_string(char *str) {
45         char *method, *tmp, *i;
46         int num_methods = 0;
47         size_t len;
48 
49 #ifdef DEBUG
50         ASSERT(str);
51 #endif
52         len = strlen(str);
53         if (len == 0)
54                 LOG_DIE("Empty methods string provided");
55 
56         /* Make a temporary copy of the string so we don't modify the original */
57         if ((tmp = str_duplicate(str)) == NULL)
58                 LOG_DIE("Cannot allocate memory for methods string buffer");
59 
60         for (i = tmp; (method = strtok(i, ",")); i = NULL) {
61                 method = str_strip_whitespace(method);
62                 method = str_tolower(method);
63                 len = strlen(method);
64 
65                 if (len == 0) continue;
66                 if (insert_method(method, len)) num_methods++;
67         }
68 
69         free(tmp);
70 
71         if (num_methods == 0)
72                 LOG_DIE("No valid methods found in string");
73 
74         return;
75 }
76 
77 /* Insert a new method into the structure */
insert_method(char * method,size_t len)78 int insert_method(char *method, size_t len) {
79         METHOD_NODE **node = &methods;
80         int cmp;
81 
82 #ifdef DEBUG
83         ASSERT(method);
84         ASSERT(strlen(method) > 0);
85 #endif
86 
87         while (*node) {
88                 cmp = str_compare(method, (*node)->method);
89                 if (cmp > 0) {
90                         node = &(*node)->right;
91                 } else if (cmp < 0) {
92                         node = &(*node)->left;
93                 } else {
94                         WARN("Method '%s' already provided", method);
95 
96                         return 0;
97                 }
98         }
99 
100         if ((*node = (METHOD_NODE *) malloc(sizeof(METHOD_NODE))) == NULL) {
101                 LOG_DIE("Cannot allocate memory for method node");
102         }
103 
104         if (((*node)->method = (char *) malloc(len + 1)) == NULL) {
105                 LOG_DIE("Cannot allocate memory for method string");
106         }
107         str_copy((*node)->method, method, len + 1);
108 
109         (*node)->left = (*node)->right = NULL;
110 
111         return 1;
112 }
113 
114 /* Search data structure for a matching method */
is_request_method(const char * str)115 int is_request_method(const char *str) {
116         METHOD_NODE *node = methods;
117         int cmp;
118 
119 #ifdef DEBUG
120         ASSERT(node);
121         ASSERT(str);
122 #endif
123 
124         if (strlen(str) == 0) return 0;
125 
126         while (node) {
127                 cmp = str_compare(str, node->method);
128                 if (cmp > 0) {
129                         node = node->right;
130                 } else if (cmp < 0) {
131                         node = node->left;
132                 } else {
133                         return 1;
134                 }
135         }
136 
137         return 0;
138 }
139 
140 /* Wrapper function to free allocated memory at program termination */
free_methods()141 void free_methods() {
142         free_node(methods);
143 
144         return;
145 }
146 
147 /* Recursively free all children of the parameter node */
free_node(METHOD_NODE * node)148 void free_node(METHOD_NODE *node) {
149         if (!node) return;
150 
151         free_node(node->left);
152         free_node(node->right);
153 
154         free(node->method);
155         free(node);
156 
157         return;
158 }
159