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