OmEspHelpers
OmWebRequest.h
1 /*
2  * OmWebRequest.h
3  * 2016-11-21
4  *
5  * This class helps parse parts of a web request. Specifically,
6  * it handles everything after the host. For example, if the
7  * full URL is "http://fish.com/content/somePage.html?a=1&b=2" then
8  * this class will operate only on "/content/somePage.html?a=1&b=2".
9  * It lets you access the path and the query values.
10  *
11  * This code is platform agnostic.
12  *
13  * It does NOT handle %-encoding in the request for now.
14  *
15  * EXAMPLE
16  *
17  * static OmWebRequest r; // static for reuse without hitting the stack space
18  * r.init("/dir/page.html?v1=One&v2=Two");
19  * const char *path = r.path; // will be "/dir/page.html"
20  * const char *v1 = r.getValue("v1"); // will be "One"
21  * const char *v2 = r.getValue("v2"); // will be "Two"
22  * const char *v3 = r.getValue("v3"); // will be NULL
23  */
24 
25 #ifndef __OmWebRequest__
26 #define __OmWebRequest__
27 
28 #include "OmUtil.h"
29 #include <vector>
30 
31 static void inplaceRequestDecode(char *r)
32 {
33  // given a legit zero-terminated char string, do, in place, the decoding
34  // of %xx and +'s. This can only make it shorter.
35  char *w = r;
36  while(char c = *r++)
37  {
38  if(c == '+')
39  c = ' ';
40  if(c == '%' && r[0] && r[1])
41  {
42  // handle %-hex character escapes
43  c = omHexToInt(r, 2);
44  r += 2;
45  }
46  *w++ = c;
47  }
48  *w++ = 0;
49 }
50 
54 {
55  static const int kRequestLengthMax = 320;
56 public:
57  const char *path;
58  std::vector<char *> query; // vector of alternating keys & values.
59  char request[kRequestLengthMax + 1];
60 
61  OmWebRequest()
62  {
63  this->path = "";
64  this->query.clear();
65  }
66 
67  void init(const char *request)
68  {
69  this->path = "";
70  this->query.clear();
71  int rIx = 0;
72  for(int ix = 0; ix <= kRequestLengthMax; ix++)
73  {
74  char c = request[rIx++];
75  this->request[ix] = c;
76 
77  if(c == 0)
78  break;
79  }
80  // pin the length safely
81  this->request[kRequestLengthMax] = 0;
82 
83  // path is always first.
84  this->path = this->request;
85 
86  // walk it and insert breaks.
87  // not very robust -- will get confused if ? = & occur in wrong order. %20s and +s figured out below.
88  char *w = this->request;
89  while(char c = *w)
90  {
91  if(c == '?'
92  || c == '='
93  || c == '&')
94  {
95  // if it's a separator, break and note it.
96  *w = 0;
97  this->query.push_back(w + 1);
98  }
99  w++;
100  }
101 
102  // now, re-walk the request local copy, and maybe swap in % and + substitutions.
103  inplaceRequestDecode(this->request);
104  for(char *r : this->query)
105  {
106  inplaceRequestDecode(r);
107  }
108  }
109 
110  const char *getValue(const char *key)
111  {
112  for(int ix = 0; ix < (int)this->query.size() - 1; ix += 2)
113  {
114  if(omStringEqual(key, this->query[ix]))
115  return this->query[ix + 1];
116  }
117  return 0;
118  }
119 
120  int getQueryCount()
121  {
122  int k = (int)this->query.size() / 2;
123  return k;
124  }
125  const char *getQueryKey(int ix)
126  {
127  if(ix < 0 || ix >= this->getQueryCount())
128  return "";
129  return this->query[ix * 2];
130  }
131  const char *getQueryValue(int ix)
132  {
133  if(ix < 0 || ix >= this->getQueryCount())
134  return "";
135  return this->query[ix * 2 + 1];
136  }
137 };
138 #endif /* defined(__OmWebRequest__) */
OmWebRequest
Definition: OmWebRequest.h:54