1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2002-2023, University of Amsterdam, 7 VU University Amsterdam 8 SWI-Prolog Solutions b.v. 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions 13 are met: 14 15 1. Redistributions of source code must retain the above copyright 16 notice, this list of conditions and the following disclaimer. 17 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in 20 the documentation and/or other materials provided with the 21 distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 POSSIBILITY OF SUCH DAMAGE. 35*/ 36 37:- module(http_client, 38 [ http_get/3, % +URL, -Reply, +Options 39 http_delete/3, % +URL, -Reply, +Options 40 http_post/4, % +URL, +In, -Reply, +Options 41 http_put/4, % +URL, +In, -Reply, +Options 42 http_patch/4, % +URL, +In, -Reply, +Options 43 http_read_data/3, % +Header, -Data, :Options 44 http_disconnect/1 % +What 45 ]). 46:- autoload(http_header,[http_post_data/3]). 47:- autoload(http_stream,[http_chunked_open/3,stream_range_open/3]). 48:- autoload(library(error),[must_be/2]). 49:- autoload(library(lists),[delete/3,select/3]). 50:- autoload(library(memfile), 51 [ new_memory_file/1, open_memory_file/4, free_memory_file/1, 52 memory_file_to_atom/3, memory_file_to_string/3, 53 memory_file_to_codes/3, open_memory_file/3 54 ]). 55:- autoload(library(option), 56 [option/3,option/2,meta_options/3,select_option/3]). 57:- autoload(library(uri),[uri_query_components/2]). 58:- autoload(library(http/http_open), 59 [http_open/3,http_close_keep_alive/1]). 60 61:- meta_predicate 62 http_read_data( , , ). 63 64:- multifile 65 http_convert_data/4, % http_read_data plugin-hook 66 http:post_data_hook/3. 67 68:- predicate_options(http_get/3, 3, 69 [ pass_to(http_open:http_open/3, 3), 70 pass_to(http_open:http_read_data/3, 3), 71 pass_to(http_json:http_read_json/3, 3) 72 ]). 73:- predicate_options(http_delete/3, 3, [pass_to(http_get/3, 3)]). 74:- predicate_options(http_post/4, 4, [pass_to(http_get/3, 3)]). 75:- predicate_options(http_put/4, 4, [pass_to(http_post/4, 4)]). 76:- predicate_options(http_read_data/3, 3, 77 [ to(any), 78 content_type(any), 79 form_data(oneof([form,mime])), 80 input_encoding(encoding), % multipart messages 81 on_filename(callable), 82 module(atom), % x-prolog data 83 variable_names(-list) 84 ]).
118 /******************************* 119 * GET * 120 *******************************/
Content-Type
header and plugins.
This predicate is the common implementation of the HTTP client
operations. The predicates http_delete/3, http_post/4 and
http_put/4 call this predicate with an appropriate
method(+Method)
option and ---for http_post/4 and http_put/4---
a post(+Data)
option.
Options are passed to http_open/3 and http_read_data/3. Other options:
headers(Fields)
from http_open/3. Provided for
backward compatibility. Note that http_version(Major-Minor)
is missing in the new version.140http_get(URL, Data, Options) :- 141 headers_option(Options, Options1, Headers), 142 option(reply_header(Headers), Options, _), 143 http_open(URL, In, Options1), 144 delete(Headers, transfer_encoding(_), Headers1), 145 call_cleanup( 146 http_read_data(In, Headers1, Data, Options), 147 close(In)). 148 149headers_option(Options, Options1, Headers) :- 150 option(headers(Headers), Options), 151 !, 152 Options1 = Options. 153headers_option(Options, [headers(Headers)|Options], Headers).
DELETE
method on the server. Arguments are the same
as for http_get/3. Typically one should pass the option
status_code(-Code)
to assess and evaluate the returned status
code. Without, codes other than 200 are interpreted as an error.
166http_delete(URL, Data, Options) :-
167 http_get(URL, Data, [method(delete)|Options]).
POST
request. Data is posted using
http_post_data/3. The HTTP server reply is returned in Reply,
using the same rules as for http_get/3.
178http_post(URL, Data, Reply, Options) :-
179 http_get(URL, Reply,
180 [ post(Data)
181 | Options
182 ]).
PUT
request. Arguments are the same as for
http_post/4.
191http_put(URL, In, Out, Options) :-
192 http_post(URL, In, Out, [method(put)|Options]).
PATCH
request. Arguments are the same as for
http_post/4.
201http_patch(URL, In, Out, Options) :-
202 http_post(URL, In, Out, [method(patch)|Options]).
to(Format)
option or based on the Content-type
in the Request. The following options are supported:
stream(+WriteStream)
)
Append the content of the message to Streammultipart/form-data
content.Without plugins, this predicate handles
Name=Value
terms.242http_read_data(Fields, Data, QOptions) :- 243 meta_options(is_meta, QOptions, Options), 244 memberchk(input(In), Fields), 245 ( http_read_data(In, Fields, Data, Options) 246 -> true 247 ; throw(error(failed(http_read_data), _)) 248 ). 249 250is_meta(on_filename). 251 252http_read_data(_In, Fields, Data, _Options) :- 253 option(status_code(Code), Fields), 254 no_content_status(Code), 255 \+ ( option(content_length(Len), Fields), 256 Len > 0 257 ), 258 !, 259 Data = ''. 260http_read_data(In, Fields, Data, Options) :- % Transfer-encoding: chunked 261 select(transfer_encoding(chunked), Fields, RestFields), 262 !, 263 setup_call_cleanup( 264 http_chunked_open(In, DataStream, []), 265 http_read_data(DataStream, RestFields, Data, Options), 266 close(DataStream)). 267http_read_data(In, Fields, Data, Options) :- 268 option(to(X), Options), 269 !, 270 ( X = stream(Stream) 271 -> ( memberchk(content_length(Bytes), Fields) 272 -> copy_stream_data(In, Stream, Bytes) 273 ; copy_stream_data(In, Stream) 274 ) 275 ; must_be(oneof([atom,string,codes]), X), 276 setup_call_cleanup( 277 new_memory_file(MemFile), 278 ( setup_call_cleanup( 279 open_memory_file(MemFile, write, Stream, 280 [encoding(octet)]), 281 ( memberchk(content_length(Bytes), Fields) 282 -> copy_stream_data(In, Stream, Bytes) 283 ; copy_stream_data(In, Stream) 284 ), 285 close(Stream)), 286 encoding(Fields, Encoding, Options), 287 memory_file_to(X, MemFile, Encoding, Data0) 288 ), 289 free_memory_file(MemFile)), 290 Data = Data0 291 ). 292http_read_data(In, Fields, Data, _) :- 293 option(content_type(ContentType), Fields), 294 is_content_type(ContentType, 'application/x-www-form-urlencoded'), 295 !, 296 http_read_data(In, Fields, Codes, [to(string)]), 297 uri_query_components(Codes, Data). 298http_read_data(In, Fields, Data, Options) :- % call hook 299 ( select_option(content_type(Type), Options, Options1) 300 -> delete(Fields, content_type(_), Fields1), 301 http_convert_data(In, [content_type(Type)|Fields1], Data, Options1) 302 ; http_convert_data(In, Fields, Data, Options) 303 ), 304 !. 305http_read_data(In, Fields, Data, Options) :- 306 http_read_data(In, Fields, Data, [to(atom)|Options]). 307 308memory_file_to(atom, MemFile, Encoding, Data) :- 309 memory_file_to_atom(MemFile, Data, Encoding). 310memory_file_to(string, MemFile, Encoding, Data) :- 311 memory_file_to_string(MemFile, Data, Encoding). 312memory_file_to(codes, MemFile, Encoding, Data) :- 313 memory_file_to_codes(MemFile, Data, Encoding). 314 315 316encoding(_Fields, Encoding, Options) :- 317 option(input_encoding(Encoding), Options), 318 !. 319encoding(Fields, utf8, _) :- 320 memberchk(content_type(Type), Fields), 321 ( sub_atom(Type, _, _, _, 'UTF-8') 322 -> true 323 ; sub_atom(Type, _, _, _, 'utf-8') 324 ), 325 !. 326encoding(_, octet, _). 327 328is_content_type(ContentType, Check) :- 329 sub_atom(ContentType, 0, Len, After, Check), 330 ( After == 0 331 -> true 332 ; sub_atom(ContentType, Len, 1, _, ';') 333 ).
341no_content_status(Code) :- 342 between(100, 199, Code), 343 !. 344no_content_status(204).
354http_convert_data(In, Fields, Data, Options) :-
355 memberchk(content_type(Type), Fields),
356 is_content_type(Type, 'application/x-prolog'),
357 !,
358 ( memberchk(content_length(Bytes), Fields)
359 -> setup_call_cleanup(
360 ( stream_range_open(In, Range, [size(Bytes)]),
361 set_stream(Range, encoding(utf8)),
362 set_stream(Range, file_name('HTTP:DATA'))
363 ),
364 read_term(Range, Data, Options),
365 close(Range))
366 ; set_stream(In, encoding(utf8)),
367 read_term(In, Data, Options)
368 ).
all
, closing all connections.
378http_disconnect(all) :-
379 http_close_keep_alive(_).
post(Data)
option
of http_open/3. The default implementation supports
prolog(Term)
, sending a Prolog term as application/x-prolog
.
387httppost_data_hook(prolog(Term), Out, HdrExtra) :-
388 setup_call_cleanup(
389 ( new_memory_file(MemFile),
390 open_memory_file(MemFile, write, Handle)
391 ),
392 ( format(Handle,
393 'Content-Type: application/x-prolog; charset=UTF-8~n~n',
394 []),
395 write_term(Handle, Term,
396 [ quoted(true),
397 ignore_ops(true),
398 fullstop(true),
399 nl(true)
400 ])
401 ),
402 close(Handle)),
403 setup_call_cleanup(
404 open_memory_file(MemFile, read, RdHandle,
405 [ free_on_close(true)
406 ]),
407 http_post_data(cgi_stream(RdHandle), Out, HdrExtra),
408 close(RdHandle))
HTTP client library
This library provides the four basic HTTP client actions:
GET
,DELETE
,POST
andPUT
. In addition, it provides http_read_data/3, which is used by library(http/http_parameters) to decodePOST
data in server applications.This library is based on http_open/3, which opens a URL as a Prolog stream. The reply is processed by http_read_data/3. The following content-types are supported. Options passed to http_get/3 and friends are passed to http_read_data/3, which in turn passes them to the conversion predicates. Support for additional content types can be added by extending the multifile predicate http_client:http_convert_data/4.
Name=Value
terms.json_object(As)
can be used to return a termjson(Attributes)
(As isterm
) or a dict (As isdict
). */