1% ---------------------------------------------------------------------- 2% BEGIN LICENSE BLOCK 3% Version: CMPL 1.1 4% 5% The contents of this file are subject to the Cisco-style Mozilla Public 6% License Version 1.1 (the "License"); you may not use this file except 7% in compliance with the License. You may obtain a copy of the License 8% at www.eclipse-clp.org/license. 9% 10% Software distributed under the License is distributed on an "AS IS" 11% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 12% the License for the specific language governing rights and limitations 13% under the License. 14% 15% The Original Code is The ECLiPSe Constraint Logic Programming System. 16% The Initial Developer of the Original Code is Cisco Systems, Inc. 17% Portions created by the Initial Developer are 18% Copyright (C) 1991-2006 Cisco Systems, Inc. All Rights Reserved. 19% 20% Contributor(s): ECRC GmbH 21% Contributor(s): IC-Parc, Imperal College London 22% 23% END LICENSE BLOCK 24% 25% System: ECLiPSe Constraint Logic Programming System 26% Version: $Id: http_client.pl,v 1.2 2009/07/16 09:11:24 jschimpf Exp $ 27% ---------------------------------------------------------------------- 28 29/* 30 RPC using HTTP/1.0 (request status line) and 31 MIME-Version:1.0 (request general header) 32 33 CLIENT 34 35 http document used is HTTP/1.0 from the Network Working Group 36 - internet draft - expiring in june, 19 1995. 37*/ 38 39 40:- module(http_client). 41 42:- comment(categories, ["Interfacing"]). 43:- comment(summary, "HTTP client library"). 44:- comment(author, "Ph. Bonnet, S. Bressan and M. Meier, ECRC Munich"). 45:- comment(copyright, "Cisco Systems, Inc"). 46:- comment(date, "$Date: 2009/07/16 09:11:24 $"). 47 48:- comment(http_client/7, [ 49 template:"http_client(+Method, +Uri, +ObjectBody, +HttpParams, -RespError, -RespParam, -RespObjectBody)", 50 summary:"Used to access HTML pages, given their URI (the method GET is applied)", 51 args:["Method":"A string","Uri":"A string","ObjectBody":"A string", 52 "HttpParams":"A list of terms as defined in the DCG grammar", 53 "RespError":"Outputs a term error(ErrorCode, ErrorPhrase), 54 where ErrorCode is he error code contained in the response 55 and ErrorPhrase is the error phrase contained in the response", 56 "RespParam":"Outputs a list of terms as defined in the DCG grammar", 57 "RespObjectBody":"Outputs the object body of the response"], 58 eg:" 59 [eclipse 1]: use_module(http). 60 http_grammar.pl compiled traceable 25048 bytes in 0.38 seconds 61 http_client.pl compiled traceable 5916 bytes in 0.47 seconds 62 http_server.pl compiled traceable 5304 bytes in 0.07 seconds 63 http.pl compiled traceable 0 bytes in 0.57 seconds 64 65 yes. 66 [eclipse 2]: http_client(\"GET\", \"http://www.ecrc.de/staff/\", \"\", [], 67 Status, Param, Resp). 68 69 Status = error(200, \"Document follows \") 70 Param = [date, server, contentType(mt(text, html))] 71 72 Resp = \"<HTML>...</HTML>\" 73 74 yes. 75 "]). 76 77 78 79 80 81:- export 82 http_compile/1, 83 http_compile/2, 84 http_open/2, 85 http_client/7. 86 87:- tool(http_compile/1, http_compile/2). 88 89 90:- use_module(http_grammar). 91 92 93/* 94http_client(+Method, +Uri, +ObjectBody, +HttpParams, 95 -RespError, -RespParams, -RespObjectBody): 96Metod and Uri and ObjectBody and String are strings 97HttpParams is a list of terms defined in the DCG (http_grammar.pl) 98Error is a term error(ErrorCode, ErrorPhrase) 99 ErrorCode: the error code contained in the response 100 ErrorCode: the error phrase contained in the response 101RespParams is a list of terms defined in DCG (http_grammar.pl) 102RespObjectBody is a string containing the object body of the response 103 104The client does: 105 - encoding of a request 106 - sending of a request 107 - reception of the response 108 - decoding of the response (nothing) 109 110HttpParams are the parameteres used to constitute the header. 111 112*/ 113 114http_client(Method, Uri, ObjectBody, HttpParams, 115 RespError, RespParams, RespObjectBody):- 116 request_enco(Method, Uri, ObjectBody, HttpParams, HostName, Request), 117 request_send(HostName, Request, Soc), 118 respons_recp(Soc, RespError, RespParams, RespObjectBody), 119 close(Soc),!. 120 121/* 122The request encoding composes a full request. 123The host name and the port are obtained from the uri 124http document p.15 125 126*/ 127request_enco(Method, Uri, ObjectBody, HttpParams, HostName, Request):- 128 hostname(Uri, HostName, PartialURL), 129 status_line(Method, PartialURL , SL), 130 resp_header(HttpParams, ObjectBody, H), 131 concat_strings(SL, H, St1), 132 concat_strings(St1, "\r\n", St2), 133 concat_strings(St2, ObjectBody, Request). 134 135/* 136url decoding for http 137*/ 138hostname(Uri, HostName, PartialURL):- 139 append_strings("http://", S, Uri), 140 open(string(S), read, St), 141 read_string(St, "/", _, HostName), close(St), 142 append_strings(HostName, PartialURL, S), !. 143 144/* 145Constitution of The header starting from the http parameters 146and the length of the object body 147*/ 148 149status_line(Method, URL, SL):- 150 concat_strings(Method, " ", St1), 151 concat_strings(St1, URL, St2), 152 concat_strings(St2, " ", St3), 153 concat_strings(St3, "HTTP/1.0\r\n", SL). 154 155resp_header(HttpParams, ObjectBody, H):- 156 params_format(HttpParams, P), 157 string_length(ObjectBody, L), 158 (L == 0 -> 159 H = P 160 ; 161 params_format([contentLength(L)], CL), 162 % could become a pb concat_strings is better 163 concat_string([P, CL], H) 164 ). 165 166params_format(HttpParams, P):- 167 params_format(HttpParams, "", P). 168 169params_format([], S, S). 170params_format([H|T], S0, S):- 171 phrase(header(H), L, _), 172 open(string(""), write, St), 173 list_to_token(L, St), 174 get_stream_info(St, name, S1), 175 close(St), 176 concat_string([S0, S1, "\r\n"], S2), 177 params_format(T, S2, S). 178 179/* 180sending of a request: 181- a socket is created and connected to hostName 182- the encoded request is sent 183*/ 184 185request_send(HostName, Request, Soc):- 186 host_and_port(HostName, HN, P), 187 socket(internet, stream, Soc), 188 connect(Soc, HN / P), 189 concat_strings(Request, "\r\n", R), 190 write(Soc, R), 191 flush(Soc). 192 193 194host_and_port(HostName, HH, 80):- 195 open(string(HostName), read, St), 196 read_string(St, ":", L, H), 197 close(St), 198 string_length(HostName, L),!, 199 atom_string(HH, H). 200host_and_port(HostName, HHH, PPP):- 201 open(string(HostName), read, St), 202 read_string(St, ":", _, H), 203 close(St), 204 concat_strings(H, ":", HH), 205 append_strings(HH, P, HostName), 206 atom_string(HHH, H), 207 atom_string(PP, P), integer_atom(PPP, PP), !. 208 209 210 211/* 212reception of a response: 213- read a message until a CRLF is found -> response status line 214 % status error management 215- analyse the response header -> length, type, encoding of the object body 216- read the object body 217*/ 218 219respons_recp(S, Error, HttpParams, ObjectBody):- 220 read_Error(S, Error),!, 221 (Error = error(200,_) -> 222 read_ParamsClient(S, Params), 223 parse_Params(Params, HttpParams), 224 read_objectBody(S, HttpParams, ObjectBody) 225 ; 226 true 227 ). 228 229read_Error(S, error(ErrorCode, ErrorPhrase)):- 230 read_string(S, end_of_line, _, SL), 231 open(string(SL), read, St), 232 token_to_list(St, L), 233 phrase(status(_, ErrorCode, ErrorPhrase), L, _), 234 close(St). 235 236/* 237general header* 238request header* 239object header* 240*/ 241read_ParamsClient(S, List):- 242 % \n instead of \r\n as in the http document 243 read_string(S, end_of_line, _Length, Elem0), 244 ( Elem0 \= "", Elem0 \= "\r" -> 245 append_strings(Elem0, "\n", Elem), 246 List = [Elem|Tail], 247 read_ParamsClient(S, Tail) 248 ; 249 List = [] 250 ). 251 252 253/* 254parsing using the DCG grammar 255*/ 256parse_Params([], []). 257parse_Params([H|T], [P|TT]):- 258 open(string(H), read, St), 259 token_to_list(St, L), 260 close(St), 261 phrase(header(P), L, _), !, 262 parse_Params(T, TT). 263 264/* 265read object body according to the content length in the http params 266*/ 267read_objectBody(S, HttpParams, ObjectBody):- 268 member(contentLength(L), HttpParams),!, 269 read_string(S, "", L, ObjectBody). 270read_objectBody(S, HttpParams, ObjectBody):- 271 member(contentType(_), HttpParams),!, 272 read_string(S, "", _, ObjectBody). 273read_objectBody(_, _, ""). 274 275/* 276No response decoding. 277*/ 278 279 280:- comment(http_open/2, [ 281 template:"http_open(+Url, -Stream)", 282 summary:"Download a web document given its URL and open a Stream to read it", 283 args:["Url":"A string","Stream":"A variable or atom"], 284 desc:html("This utility downloads a web document (given its URL) into a 285 string stream and returns that string stream's identifier for reading."), 286 eg:" 287 [eclipse 1]: lib(http_client). 288 yes. 289 [eclipse 2]: http_open(\"http://icparc.ic.ac.uk/index.html\",S), 290 read_string(S, end_of_line, _, L). 291 S = 19 292 L = \"<!DOCTYPE HTML PUBLIC \\\"-//W3C//DTD HTML 3.2//EN\\\">\" 293 yes. 294 "]). 295 296http_open(URL, Stream) :- 297 http_client("GET", URL, "", [], Error, _Params, Response), 298 ( Error = error(200, _OK) -> 299 open(string(Response), read, Stream) 300 ; 301 fail 302 ). 303 304 305:- comment(http_compile/1, [ 306 template:"http_compile(+Url)", 307 summary:"Compile an ECLiPSe source file, given its URL", 308 args:["Url":"A string"], 309 desc:html("This utility downloads an eclipse source file (given its URL) 310 and compiles it. Note that this represents a security risk: the downloaded 311 code may contain Eclipse commands that are executed on your computer. 312 Make sure you trust the code that you download!"), 313 eg:" 314 [eclipse 1]: lib(http_client). 315 yes. 316 [eclipse 2]: http_compile(\"http://icparc.ic.ac.uk/eclipse/examples/sendmore.pl\"). 317 yes. 318 [eclipse 8]: sendmore1(X). 319 X = [9, 5, 6, 7, 1, 0, 8, 2] More? (;) 320 no (more) solution. 321 "]). 322 323http_compile(URL, Module) :- 324 http_open(URL, Stream), 325 compile_stream(Stream)@Module, 326 close(Stream). 327 328