A simple web service over HTTP library. Calls a HTTP server via GET, and returns the response wrapped in a XML parser. All calls are synchronous. Needs the NetServicesMin, DNSResolver, TcpLineStream and spxml libraries. The code for URL handling has been copied directly from the original NetServices library (Thanks to Donatien!).

Committer:
hlipka
Date:
Tue Jan 11 23:00:09 2011 +0000
Revision:
0:5e8527b638e1
Child:
1:62e112d14c8f
initial version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hlipka 0:5e8527b638e1 1 #include "Timer.h"
hlipka 0:5e8527b638e1 2
hlipka 0:5e8527b638e1 3 #include "webservice.h"
hlipka 0:5e8527b638e1 4
hlipka 0:5e8527b638e1 5 #include "spxmlnode.hpp"
hlipka 0:5e8527b638e1 6 #include "spxmlhandle.hpp"
hlipka 0:5e8527b638e1 7
hlipka 0:5e8527b638e1 8 #include "dnsresolve.h"
hlipka 0:5e8527b638e1 9
hlipka 0:5e8527b638e1 10 void WebService::onTCPSocketEvent(TCPSocketEvent e) {
hlipka 0:5e8527b638e1 11 // printf("New TCPSocketEvent: %d\n",e);
hlipka 0:5e8527b638e1 12 switch (e) {
hlipka 0:5e8527b638e1 13 case TCPSOCKET_CONNECTED:
hlipka 0:5e8527b638e1 14 _connected = true;
hlipka 0:5e8527b638e1 15 _connecting=false;
hlipka 0:5e8527b638e1 16 break;
hlipka 0:5e8527b638e1 17
hlipka 0:5e8527b638e1 18 case TCPSOCKET_READABLE:
hlipka 0:5e8527b638e1 19 break;
hlipka 0:5e8527b638e1 20 case TCPSOCKET_WRITEABLE:
hlipka 0:5e8527b638e1 21 break;
hlipka 0:5e8527b638e1 22
hlipka 0:5e8527b638e1 23 case TCPSOCKET_CONTIMEOUT:
hlipka 0:5e8527b638e1 24 case TCPSOCKET_CONRST:
hlipka 0:5e8527b638e1 25 case TCPSOCKET_CONABRT:
hlipka 0:5e8527b638e1 26 case TCPSOCKET_ERROR:
hlipka 0:5e8527b638e1 27 case TCPSOCKET_DISCONNECTED: {
hlipka 0:5e8527b638e1 28 // don't close the real socket here, as this may skip the already received data
hlipka 0:5e8527b638e1 29 _connected = false;
hlipka 0:5e8527b638e1 30 _connecting=false;
hlipka 0:5e8527b638e1 31 }
hlipka 0:5e8527b638e1 32 break;
hlipka 0:5e8527b638e1 33 }
hlipka 0:5e8527b638e1 34 }
hlipka 0:5e8527b638e1 35
hlipka 0:5e8527b638e1 36 WebService::WebService(const char* url):_url(url) {
hlipka 0:5e8527b638e1 37 _closed=false;
hlipka 0:5e8527b638e1 38 _readpos=0;
hlipka 0:5e8527b638e1 39 _readlen=0;
hlipka 0:5e8527b638e1 40 _readpos=0;
hlipka 0:5e8527b638e1 41 _readlen=0;
hlipka 0:5e8527b638e1 42
hlipka 0:5e8527b638e1 43 _socket.setOnEvent(this,&WebService::onTCPSocketEvent);
hlipka 0:5e8527b638e1 44 }
hlipka 0:5e8527b638e1 45
hlipka 0:5e8527b638e1 46 SP_XmlDomParser* WebService::callService() {
hlipka 0:5e8527b638e1 47 Url url;
hlipka 0:5e8527b638e1 48 url.fromString(_url);
hlipka 0:5e8527b638e1 49
hlipka 0:5e8527b638e1 50 string request=string("GET ").append(_url).append(" HTTP/1.0\r\n\r\n");
hlipka 0:5e8527b638e1 51
hlipka 0:5e8527b638e1 52 IpAddr addr;
hlipka 0:5e8527b638e1 53 if (!url.getHostIp(&addr)) {
hlipka 0:5e8527b638e1 54 DNSResolver dr;
hlipka 0:5e8527b638e1 55 addr=dr.resolveName(url.getHost().c_str());
hlipka 0:5e8527b638e1 56 }
hlipka 0:5e8527b638e1 57 // printf("host ip=%i.%i.%i.%i\n",addr[0],addr[1],addr[2],addr[3]);
hlipka 0:5e8527b638e1 58
hlipka 0:5e8527b638e1 59 int port=0==url.getPort()?80:url.getPort();
hlipka 0:5e8527b638e1 60
hlipka 0:5e8527b638e1 61 Host host(addr, port);
hlipka 0:5e8527b638e1 62
hlipka 0:5e8527b638e1 63 TCPSocketErr bindErr = _socket.connect(host);
hlipka 0:5e8527b638e1 64
hlipka 0:5e8527b638e1 65 if (bindErr != 0) {
hlipka 0:5e8527b638e1 66 printf("connection error %i\n", bindErr);
hlipka 0:5e8527b638e1 67 return false;
hlipka 0:5e8527b638e1 68 }
hlipka 0:5e8527b638e1 69
hlipka 0:5e8527b638e1 70 // wait for connection established
hlipka 0:5e8527b638e1 71 _connecting=true;
hlipka 0:5e8527b638e1 72 mbed::Timer tmr;
hlipka 0:5e8527b638e1 73 tmr.start();
hlipka 0:5e8527b638e1 74
hlipka 0:5e8527b638e1 75 while (_connecting) {
hlipka 0:5e8527b638e1 76 Net::poll();
hlipka 0:5e8527b638e1 77 wait(0.1);
hlipka 0:5e8527b638e1 78 if (tmr.read()>10) {
hlipka 0:5e8527b638e1 79 printf("reached timeout\n");
hlipka 0:5e8527b638e1 80 break;
hlipka 0:5e8527b638e1 81 }
hlipka 0:5e8527b638e1 82 }
hlipka 0:5e8527b638e1 83
hlipka 0:5e8527b638e1 84 if (!_connected) {
hlipka 0:5e8527b638e1 85 printf("error - could not connect (timeout)\n");
hlipka 0:5e8527b638e1 86 return NULL;
hlipka 0:5e8527b638e1 87 }
hlipka 0:5e8527b638e1 88 // printf("send request[%s]\n",request.c_str());
hlipka 0:5e8527b638e1 89 _socket.send(request.c_str(),request.length());
hlipka 0:5e8527b638e1 90 Net::poll();
hlipka 0:5e8527b638e1 91
hlipka 0:5e8527b638e1 92 if (!_connected)
hlipka 0:5e8527b638e1 93 return NULL;
hlipka 0:5e8527b638e1 94
hlipka 0:5e8527b638e1 95 string firstLine=readResponseLine();
hlipka 0:5e8527b638e1 96 // todo: parse for HTTP response
hlipka 0:5e8527b638e1 97 // response must be for HTTP/1.0, and be 200
hlipka 0:5e8527b638e1 98 if (0!=firstLine.compare("HTTP/1.0 200 OK"))
hlipka 0:5e8527b638e1 99 {
hlipka 0:5e8527b638e1 100 printf("call not sucessfull, response=%s\n",firstLine.c_str());
hlipka 0:5e8527b638e1 101 return NULL;
hlipka 0:5e8527b638e1 102 }
hlipka 0:5e8527b638e1 103 // skip headers
hlipka 0:5e8527b638e1 104 while (true) {
hlipka 0:5e8527b638e1 105 string line=readResponseLine();
hlipka 0:5e8527b638e1 106 // printf("header=[%s]\n",line.c_str());
hlipka 0:5e8527b638e1 107 if (0==line.length())
hlipka 0:5e8527b638e1 108 break;
hlipka 0:5e8527b638e1 109 }
hlipka 0:5e8527b638e1 110 SP_XmlDomParser *parser=new SP_XmlDomParser();
hlipka 0:5e8527b638e1 111 while (true) {
hlipka 0:5e8527b638e1 112 string line=readResponseLine();
hlipka 0:5e8527b638e1 113 // printf("content=[%s]\n",line.c_str());
hlipka 0:5e8527b638e1 114 parser->append(line.c_str(),line.length());
hlipka 0:5e8527b638e1 115 if (0==line.length())
hlipka 0:5e8527b638e1 116 break;
hlipka 0:5e8527b638e1 117 }
hlipka 0:5e8527b638e1 118
hlipka 0:5e8527b638e1 119 return parser;
hlipka 0:5e8527b638e1 120 }
hlipka 0:5e8527b638e1 121
hlipka 0:5e8527b638e1 122 void WebService::close() {
hlipka 0:5e8527b638e1 123 if (_closed)
hlipka 0:5e8527b638e1 124 return;
hlipka 0:5e8527b638e1 125
hlipka 0:5e8527b638e1 126 while (_connected) {
hlipka 0:5e8527b638e1 127 Net::poll();
hlipka 0:5e8527b638e1 128 // read remaining data
hlipka 0:5e8527b638e1 129 int err=_socket.recv(_readbuf,BUFSIZE-1);
hlipka 0:5e8527b638e1 130 if (err<=0)
hlipka 0:5e8527b638e1 131 break;
hlipka 0:5e8527b638e1 132 }
hlipka 0:5e8527b638e1 133
hlipka 0:5e8527b638e1 134 while (true) {
hlipka 0:5e8527b638e1 135 Net::poll();
hlipka 0:5e8527b638e1 136 // read remaining data
hlipka 0:5e8527b638e1 137 int err=_socket.recv(_readbuf,BUFSIZE-1);
hlipka 0:5e8527b638e1 138 if (err<=0)
hlipka 0:5e8527b638e1 139 break;
hlipka 0:5e8527b638e1 140 }
hlipka 0:5e8527b638e1 141
hlipka 0:5e8527b638e1 142 _socket.resetOnEvent();
hlipka 0:5e8527b638e1 143 _socket.close();
hlipka 0:5e8527b638e1 144
hlipka 0:5e8527b638e1 145 _closed=true;
hlipka 0:5e8527b638e1 146 }
hlipka 0:5e8527b638e1 147
hlipka 0:5e8527b638e1 148
hlipka 0:5e8527b638e1 149
hlipka 0:5e8527b638e1 150 string WebService::readResponseLine() {
hlipka 0:5e8527b638e1 151 string r;
hlipka 0:5e8527b638e1 152 bool got_r=false;
hlipka 0:5e8527b638e1 153
hlipka 0:5e8527b638e1 154 int emptyCount=0;
hlipka 0:5e8527b638e1 155 while (true) {
hlipka 0:5e8527b638e1 156 Net::poll();
hlipka 0:5e8527b638e1 157 if (_readlen>_readpos) {
hlipka 0:5e8527b638e1 158 while (_readbuf[_readpos]!=0 && _readpos<_readlen) {
hlipka 0:5e8527b638e1 159 char c=_readbuf[_readpos++];
hlipka 0:5e8527b638e1 160 if (!got_r) {
hlipka 0:5e8527b638e1 161 if (c=='\r') {
hlipka 0:5e8527b638e1 162 got_r=true;
hlipka 0:5e8527b638e1 163 } else {
hlipka 0:5e8527b638e1 164 r.push_back(c);
hlipka 0:5e8527b638e1 165 }
hlipka 0:5e8527b638e1 166 } else {
hlipka 0:5e8527b638e1 167 if (c=='\n') {
hlipka 0:5e8527b638e1 168 return r;
hlipka 0:5e8527b638e1 169 } else {
hlipka 0:5e8527b638e1 170 r.push_back('\r'); // push missed \r also, so push it to string
hlipka 0:5e8527b638e1 171 r.push_back(c);
hlipka 0:5e8527b638e1 172 got_r=false;
hlipka 0:5e8527b638e1 173 }
hlipka 0:5e8527b638e1 174 }
hlipka 0:5e8527b638e1 175 }
hlipka 0:5e8527b638e1 176 } else {
hlipka 0:5e8527b638e1 177 int err=_socket.recv(_readbuf,BUFSIZE-1);
hlipka 0:5e8527b638e1 178 if (err < 0) {
hlipka 0:5e8527b638e1 179 printf("error while receiving data: %i!\n",err);
hlipka 0:5e8527b638e1 180 break;
hlipka 0:5e8527b638e1 181 } else if (err>0) {
hlipka 0:5e8527b638e1 182 emptyCount=0;
hlipka 0:5e8527b638e1 183 _readbuf[err]=0;
hlipka 0:5e8527b638e1 184 _readlen=err;
hlipka 0:5e8527b638e1 185 _readpos=0;
hlipka 0:5e8527b638e1 186 // printf("r=%s\n",_readbuf);
hlipka 0:5e8527b638e1 187 }
hlipka 0:5e8527b638e1 188 else
hlipka 0:5e8527b638e1 189 {
hlipka 0:5e8527b638e1 190 // when we don't receive any data, and are not connected
hlipka 0:5e8527b638e1 191 // we stop because there isn't anything left
hlipka 0:5e8527b638e1 192 if (emptyCount++>2)
hlipka 0:5e8527b638e1 193 if (!_connected)
hlipka 0:5e8527b638e1 194 break;
hlipka 0:5e8527b638e1 195 }
hlipka 0:5e8527b638e1 196 }
hlipka 0:5e8527b638e1 197 wait(0.1);
hlipka 0:5e8527b638e1 198 }
hlipka 0:5e8527b638e1 199 return r;
hlipka 0:5e8527b638e1 200 }