Commit 7264ac9e72d08e1d90a17e5fd4e773673de4a4f5

Authored by Totoro
1 parent 754d13f2

add the missing files CXM_http_get.anubis and CXM_https_get.anubis since a long time.

add XML RPC client
web/CXM_http_get.anubis 0 → 100644
  1 + *Project* The Anubis Project
  2 +
  3 + *Title* Getting a document from the Web.
  4 +
  5 + *Copyright* Copyright (c) Alain Prouté 2001.
  6 +
  7 +
  8 + *Author* Alain Prouté
  9 +
  10 +
  11 +
  12 + *Overview*
  13 + This file defines the function 'http_get' which retrieves a document from the world
  14 + wide web (a similar function 'https_get' for secured documents is defined in
  15 + 'https_get.anubis'). The function simulates the behavior of a browser, at least just
  16 + what is needed to retrieve the document. It does not display the document, but returns
  17 + it (if found) in the form of a string. It also returns the response line from the
  18 + server, and the list af all HTTP headers.
  19 +
  20 + The function 'http_get' takes the following arguments:
  21 +
  22 + - the name of the server to which the request is to be sent,
  23 + - the name (including the path) of the document on this server,
  24 + - a list of headers to be added to mandatory standard headers,
  25 + - a list of 'arguments' in the form of pairs of strings '(name,value)' to be sent as
  26 + the body of the request.
  27 +
  28 +
  29 + The result returned by 'http_get' has the following type, which defines the problems
  30 + which may happen:
  31 +
  32 +
  33 +read tools/basis.anubis
  34 +read system/string.anubis
  35 +read web/CXM_common.anubis
  36 +read web/CXM_http_get_common.anubis
  37 +
  38 +
  39 +public type HTTP_GET_Result:
  40 + cannot_resolve_server_name(DNS_Result),
  41 + cannot_connect_to_server(NetworkConnectError),
  42 + transmission_problem,
  43 + request_refused_by_server,
  44 + ok(String response, // HTTP response line from the server
  45 + List(HTTP_header) headers, // HTTP headers received from the server
  46 + String document). // The HTML document itself
  47 +
  48 +
  49 +public define HTTP_GET_Result
  50 + http_get
  51 + ( //-------- example: -----------------------
  52 + String server_name, // "www.machin.com"
  53 + String document_name, // "/truc/bidule.html"
  54 + List(HTTP_header) headers, // [http_header("Cookie","..."),...]
  55 + List(HTTP_argument) arguments // [http_argument("ga","bu"),...]
  56 + ).
  57 +
  58 + The same one without the 'headers' argument:
  59 +
  60 +public define HTTP_GET_Result
  61 + http_get
  62 + ( //-------- example: -----------------------
  63 + String server_name, // "www.machin.com"
  64 + String document_name, // "/truc/bidule.html"
  65 + List(HTTP_argument) arguments // [http_argument("ga","bu"),...]
  66 + ) = http_get(server_name,document_name,[],arguments).
  67 +
  68 +
  69 +
  70 + This file also defines the command 'http_get' to be used directly from the system
  71 + prompt. To learn about the syntax, just type 'http_get' at the system prompt, or have
  72 + a look at the end of this file
  73 +
  74 + --- That's all for public definitions. ------------------------------------------------
  75 +
  76 +
  77 +
  78 + We need two functions for sending and receiving bytes.
  79 +
  80 +define Maybe(One)
  81 + send
  82 + (
  83 + RWStream conn, // where to send the text
  84 + String text, // the text to be sent
  85 + Word32 n // start sending at character number 'n' in 'text'
  86 + ) =
  87 + if nth(to_Int(n),text) is
  88 + {
  89 + failure then success(unique),
  90 + success(c) then
  91 + if conn <- c is
  92 + {
  93 + failure then failure,
  94 + success(_) then send(conn,text,n+1)
  95 + }
  96 + }.
  97 +
  98 +define Maybe(String)
  99 + receive_text_chunk
  100 + (
  101 + RWStream conn,
  102 + List(Word8) so_far,
  103 + Word32 count
  104 + ) =
  105 + if count = 100
  106 + then success(implode(reverse(so_far)))
  107 + else if *conn is // *conn waits for data to be readable from connection
  108 + {
  109 + failure then success(implode(reverse(so_far))), // means 'connection closed by peer'
  110 + success(c) then receive_text_chunk(conn,[c . so_far],count+1)
  111 + }.
  112 +
  113 +
  114 +define HTTP_GET_Result
  115 + receive
  116 + (
  117 + RWStream conn,
  118 + String headers,
  119 + String text_so_far,
  120 + Bool double_crlf_seen
  121 + ) =
  122 + if receive_text_chunk(conn,[],0) is
  123 + {
  124 + failure then if separate_headers(headers) is
  125 + {
  126 + [ ] then ok("",[],text_so_far),
  127 + [h . t] then if h is http_header(a,b) then ok(a,t,text_so_far)
  128 + },
  129 +
  130 + success(s) then
  131 + if s = ""
  132 + then if separate_headers(headers) is
  133 + {
  134 + [ ] then ok("",[],text_so_far),
  135 + [h . t] then if h is http_header(a,b) then ok(a,t,text_so_far)
  136 + }
  137 + else with new_s = text_so_far+s,
  138 + if double_crlf_seen
  139 + then receive(conn,headers,new_s,true)
  140 + else if has_double_crlf(new_s) is
  141 + {
  142 + failure then receive(conn,headers,new_s,false),
  143 + success(n) then
  144 + if sub_string(new_s,n+4,length(new_s)-n-4) is
  145 + {
  146 + failure then alert,
  147 + success(s1) then
  148 + if sub_string(new_s,0,n) is
  149 + {
  150 + failure then alert,
  151 + success(h) then receive(conn,h,s1,true)
  152 + }
  153 + }
  154 + }
  155 + }.
  156 +
  157 +
  158 +
  159 + The next function has a valid TCP/IP connection to the server, and tries to retrieve
  160 + the document.
  161 +
  162 +
  163 +define HTTP_GET_Result
  164 + http_get
  165 + (
  166 + Bool print_all,
  167 + RWStream conn,
  168 + String server_name,
  169 + String document_name,
  170 + List(HTTP_header) headers,
  171 + List(HTTP_argument) arguments,
  172 + ) =
  173 + //
  174 + // Send the HTTP request, and receive the answer:
  175 + //
  176 + with body = format_http_args(arguments),
  177 + with request = (if arguments = [] then "GET " else "POST ")
  178 + + document_name + " HTTP/1.0" + crlf +
  179 + "Host: " + server_name + crlf +
  180 + "Accept-Charset: iso-8859-1,*,utf-8" + crlf +
  181 + (if arguments = [] then ""
  182 + else "Content-type: application/x-www-form-urlencoded" + crlf +
  183 + "Content-length: " + to_decimal(length(body))+ crlf) +
  184 + format_headers(headers) +
  185 + crlf +
  186 + body,
  187 + (if print_all then
  188 + (
  189 + print("----- request ----\n");
  190 + print(request);
  191 + print("\n")
  192 + ) else unique);
  193 + if send(conn,request,0) is
  194 + {
  195 + failure then transmission_problem,
  196 + success(_) then receive(conn,"","",false)
  197 + }.
  198 +
  199 +
  200 + The next function retrieves the document using the numerical (resolved) server address.
  201 +
  202 +define HTTP_GET_Result
  203 + http_get
  204 + (
  205 + Bool print_all,
  206 + Word32 server_addr,
  207 + Word32 server_port,
  208 + String server_name,
  209 + String document_name,
  210 + List(HTTP_header) headers,
  211 + List(HTTP_argument) arguments,
  212 + ) =
  213 + //
  214 + // try to connect to the server before sending the request
  215 + //
  216 + if (Result(NetworkConnectError,RWStream))connect(server_addr,server_port) is
  217 + {
  218 + error(e) then cannot_connect_to_server(e),
  219 + ok(conn) then http_get(print_all,conn,server_name,document_name,headers,arguments)
  220 + }.
  221 +
  222 +
  223 +define HTTP_GET_Result
  224 + http_get
  225 + (
  226 + Bool print_all,
  227 + String server_name,
  228 + String document_name,
  229 + List(HTTP_header) headers,
  230 + List(HTTP_argument) arguments,
  231 + ) =
  232 + if separate_name_port(server_name,80) is (name,port) then
  233 + //
  234 + // resolve server name and call 'http_get' with numeric server address:
  235 + //
  236 + with a = dns(name),
  237 + if a is ok(addr)
  238 + then http_get(print_all,addr,port,name,document_name,headers,arguments)
  239 + else cannot_resolve_server_name(a).
  240 +
  241 +
  242 + Now, here is our public tool:
  243 +
  244 +define HTTP_GET_Result
  245 + http_get
  246 + (
  247 + String server_name,
  248 + String document_name,
  249 + List(HTTP_header) headers,
  250 + List(HTTP_argument) arguments,
  251 + ) = http_get(false,server_name,document_name,headers,arguments).
  252 +
  253 +
  254 +
  255 + Finally, we construct the executable module 'http_get':
  256 +
  257 +define One
  258 + recall_syntax =
  259 + print("\nUsage: http_get <server> <document> [options] =<header> <value> ... -<arg> <value> ...\n");
  260 + print(" Options are:\n");
  261 + print(" -print_all print request, response line, headers and document\n");
  262 + print(" (default is to print only the document)\n").
  263 +
  264 +
  265 +
  266 +
  267 +global define One
  268 + http_get
  269 + (
  270 + List(String) args
  271 + ) =
  272 + if args is
  273 + {
  274 + [ ] then recall_syntax,
  275 + [server . t] then if t is
  276 + {
  277 + [ ] then recall_syntax,
  278 + [document . rest] then
  279 + with print_all = member(rest,"-print_all"),
  280 + headers = get_headers(rest),
  281 + arguments = get_arguments(rest),
  282 + if http_get(print_all,server,document,headers,arguments) is
  283 + {
  284 + cannot_resolve_server_name(dns_error) then
  285 + print("Cannot resolve server name: " + format(dns_error) + ".\n"),
  286 +
  287 + cannot_connect_to_server(connect_error) then
  288 + print("Cannot connect to server: " + format(connect_error) + ".\n"),
  289 +
  290 + transmission_problem then
  291 + print("Transmission problem.\n"),
  292 +
  293 + request_refused_by_server then
  294 + print("The request has been refused by server: " + server + ".\n"),
  295 +
  296 + ok(response,headers1,document1) then
  297 + (
  298 + if print_all
  299 + then (
  300 + print("\n----- response ----\n");
  301 + print(response);
  302 + print("\n----- headers -----\n");
  303 + print_headers(headers1);
  304 + print("----- document ----\n")
  305 + ) else unique
  306 + );
  307 + print(document1) // on the screen (use a redirection to get it in a file)
  308 + }
  309 + }
  310 + }.
  311 +
... ...
web/CXM_https_get.anubis 0 → 100644
  1 +
  2 + *Project* The Anubis Project
  3 +
  4 + *Title* Getting a document from the secured Web.
  5 +
  6 + *Copyright* Copyright (c) Alain Prouté 2001.
  7 +
  8 +
  9 + *Author* Alain Prouté
  10 +
  11 +
  12 + *Overview*
  13 + This file defines the function 'https_get' which retrieve a document from the world
  14 + wide web in secured mode (HTTPS). The function is analogous to 'http_get', to be found
  15 + in 'web/http_get.anubis'.
  16 +
  17 + The function simulates the behavior of a browser, at least just what is needed to
  18 + retrieve the document. It does not display the document, but returns it (if found) in
  19 + the form of a string.
  20 +
  21 + The function 'https_get' takes the following operands:
  22 +
  23 + - the name of the server to which the request is to be sent,
  24 + - the name (including the path) of the document on this server,
  25 + - a list of headers to be added to mandatory standard headers,
  26 + - a list of 'arguments' to be sent as the body of the request (web arguments).
  27 + - an accept policy function (see below), for accepting X.509 certificates in case of
  28 + a problem.
  29 +
  30 + The result returned by 'https_get' has the following type, which defines the problems
  31 + which may happen:
  32 +
  33 +
  34 +read tools/basis.anubis
  35 +read system/string.anubis
  36 +read html.anubis
  37 +read http_get_common.anubis
  38 +read http_server.anubis
  39 +read common.anubis
  40 +
  41 +
  42 +public type HTTPS_GET_Result:
  43 + cannot_resolve_server_name(DNS_Result),
  44 + ssl_connect_error(SSLConnectError),
  45 + transmission_problem,
  46 + request_refused_by_server,
  47 + ok(String response,
  48 + List(HTTP_header) headers,
  49 + String document).
  50 +
  51 + Cookies are among headers. See 'web/cookies.anubis' for cookies handling.
  52 +
  53 +
  54 + Note: The types 'DNS_Result' and 'SSLConnectError' are defined in 'predefined.anubis'.
  55 +
  56 +public define HTTPS_GET_Result
  57 + https_get
  58 + (
  59 + String server_name,
  60 + String document_name,
  61 + List(HTTP_header) headers,
  62 + List(HTTP_argument) arguments,
  63 + (Maybe(X509)) -> Bool accept_policy
  64 + ).
  65 +
  66 + The same one without the 'headers' argument:
  67 +
  68 +public define HTTPS_GET_Result
  69 + https_get
  70 + (
  71 + String server_name,
  72 + String document_name,
  73 + List(HTTP_argument) arguments,
  74 + (Maybe(X509)) -> Bool accept_policy
  75 + ) = https_get(server_name,document_name,[],arguments,accept_policy).
  76 +
  77 + The main difference with 'http_get' is the presence of the 'accept_policy'
  78 + argument. 'accept_policy' is the function which determines your personal policy for
  79 + accepting a server certificate, if it is the case that either this certificate is
  80 + invalid (or missing), or if its common name does not match the server name, that is to
  81 + say if 'open_SSL_connection' (defined in 'predefined.anubis') did not already accept
  82 + it.
  83 +
  84 + 'X509' is an 'opaque' type defined in 'predefined.anubis'. It is 'opaque' in the sens
  85 + that no alternative of this type is directly accessible to you (despite the fact that
  86 + the type is public).
  87 +
  88 + An accept policy function takes (maybe) an X.509 certificate as its unique argument, so
  89 + that the decision may be taken with the suspect certificate at hand. It must return
  90 + 'true' for accepting, and 'false' for refusing.
  91 +
  92 + You may use the following default accept policy function:
  93 +
  94 +public define Bool
  95 + default_accept_policy
  96 + (
  97 + Maybe(X509) suspect_certificate
  98 + ) = false.
  99 +
  100 + That is, never accept a certificate which cannot be successfully verified by
  101 + 'open_SSL_connection'. Notice that this is not a paranoid behavior, but a normal
  102 + behavior. Nevertheless, you still have the possibility to weaken this behavior by
  103 + using another accept policy function. Be very careful when writing this function,
  104 + because this may weaken your security. This function may for example show the
  105 + certificate and ask for user input for accepting it. It may also check the certificate
  106 + fingerprint against a data base, etc...
  107 +
  108 + Another accept policy function is defined in this file:
  109 +
  110 +public define Bool
  111 + command_line_accept_policy
  112 + (
  113 + Maybe(X509) suspect_certificate
  114 + ).
  115 +
  116 + It is used by the command line module 'https_get.adm'. If the certificate is not
  117 + accepted by 'open_SSL_connection', this function prints the certificate on the screen,
  118 + and ask the user for acceptation. It also asks the user for accepting the certificate
  119 + for ever.
  120 +
  121 + It is likely that you will need an accept policy function of your own. See the
  122 + definition of 'command_line_accept_policy' below for information and
  123 + 'predefined.anubis' for the tools enabling the manipulation of X.509 certificates.
  124 + Certificates that you trust are stored into the directory declared under the symbol
  125 + 'ca' (for 'Certificate Authorities') in your configuration file. Any certificate
  126 + present in this directory is trusted without any condition.
  127 +
  128 + This file defines the module 'https_get' to be used directly from the command line. To
  129 + learn about the syntax, just type 'https_get' at the system prompt, or have a look at
  130 + the end of this file.
  131 +
  132 +
  133 +
  134 +
  135 + --- That's all for public definitions. ------------------------------------------------
  136 +
  137 +
  138 +
  139 +
  140 +
  141 +
  142 +
  143 +
  144 +define Maybe(String)
  145 + receive_text_chunk
  146 + (
  147 + SSL_Connection conn
  148 + ) =
  149 + read(conn,100,1000).
  150 +
  151 +
  152 +
  153 +
  154 +define HTTPS_GET_Result
  155 + receive
  156 + (
  157 + SSL_Connection conn,
  158 + String headers,
  159 + String text_so_far,
  160 + Bool double_crlf_seen
  161 + ) =
  162 + if receive_text_chunk(conn) is
  163 + {
  164 + failure then if separate_headers(headers) is
  165 + {
  166 + [ ] then ok("",[],text_so_far),
  167 + [h . t] then if h is http_header(a,b) then ok(a,t,text_so_far)
  168 + },
  169 +
  170 + success(s) then
  171 + if s = ""
  172 + then if separate_headers(headers) is
  173 + {
  174 + [ ] then ok("",[],text_so_far),
  175 + [h . t] then if h is http_header(a,b) then ok(a,t,text_so_far)
  176 + }
  177 + else with new_s = text_so_far+s,
  178 + if double_crlf_seen
  179 + then receive(conn,headers,new_s,true)
  180 + else if has_double_crlf(new_s) is
  181 + {
  182 + failure then receive(conn,headers,new_s,false),
  183 + success(n) then
  184 + if sub_string(new_s,n+4,length(new_s)-n-4) is
  185 + {
  186 + failure then alert,
  187 + success(s1) then
  188 + if sub_string(new_s,0,n) is
  189 + {
  190 + failure then alert,
  191 + success(h) then receive(conn,h,s1,true)
  192 + }
  193 + }
  194 + }
  195 + }.
  196 +
  197 +
  198 +
  199 + The next function has a valid SSL connection to the server, and tries to retrieve the
  200 + document.
  201 +
  202 +define HTTPS_GET_Result
  203 + https_get
  204 + (
  205 + Bool print_all,
  206 + SSL_Connection conn,
  207 + String server_name,
  208 + String document_name,
  209 + List(HTTP_header) headers,
  210 + List(HTTP_argument) arguments
  211 + ) =
  212 + //
  213 + // Send the HTTP request, and receive the answer:
  214 + //
  215 + with body = format_http_args(arguments),
  216 + with request = (if arguments = [] then "GET " else "POST ")
  217 + + document_name + " HTTP/1.0" + crlf +
  218 + "Host: " + server_name + crlf +
  219 + "Accept-Charset: iso-8859-1,*,utf-8" + crlf +
  220 + (if arguments = [] then ""
  221 + else "Content-type: application/x-www-form-urlencoded" + crlf +
  222 + "Content-length: " + to_decimal(length(body))+ crlf) +
  223 + format_headers(headers) +
  224 + crlf +
  225 + body,
  226 + (if print_all then
  227 + (
  228 + print("Sending request:\n");
  229 + print(request);
  230 + print("\n")
  231 + ) else unique);
  232 + if write(conn,request) is
  233 + {
  234 + failure then transmission_problem,
  235 + success(_) then receive(conn,"","",false)
  236 + }.
  237 +
  238 +
  239 + The next function retrieves the document using the numerical (resolved) server address.
  240 +
  241 +define HTTPS_GET_Result
  242 + https_get
  243 + (
  244 + Bool print_all,
  245 + Word32 server_addr,
  246 + Word32 server_port,
  247 + String server_name,
  248 + String document_name,
  249 + List(HTTP_header) headers,
  250 + List(HTTP_argument) arguments,
  251 + (Maybe(X509)) -> Bool accept_policy
  252 + ) =
  253 + if open_SSL_connection(server_name,server_addr,server_port,accept_policy) is
  254 + {
  255 + error(msg) then ssl_connect_error(msg),
  256 + ok(conn) then https_get(print_all,conn,server_name,document_name,headers,arguments)
  257 + }.
  258 +
  259 +
  260 +
  261 +define HTTPS_GET_Result
  262 + https_get
  263 + (
  264 + Bool print_all,
  265 + String server_name,
  266 + String document_name,
  267 + List(HTTP_header) headers,
  268 + List(HTTP_argument) arguments,
  269 + (Maybe(X509)) -> Bool accept_policy
  270 + ) =
  271 + if separate_name_port(server_name,443) is (name,port) then
  272 + //
  273 + // resolve server name and call 'https_get' with numeric server address:
  274 + //
  275 + with a = dns(name),
  276 + if a is ok(addr)
  277 + then https_get(print_all,addr,port,name,document_name,headers,arguments,accept_policy)
  278 + else cannot_resolve_server_name(a).
  279 +
  280 +
  281 +
  282 + Now, here is our public tool:
  283 +
  284 +public define HTTPS_GET_Result
  285 + https_get
  286 + (
  287 + String server_name,
  288 + String document_name,
  289 + List(HTTP_header) headers,
  290 + List(HTTP_argument) arguments,
  291 + (Maybe(X509)) -> Bool accept_policy
  292 + ) = https_get(false,server_name,document_name,headers,arguments,accept_policy).
  293 +
  294 +
  295 +
  296 +
  297 +
  298 + Finally, we construct the command line executable module 'https_get.adm':
  299 +
  300 +define One
  301 + syntax_https_get =
  302 + print("\nUsage: https_get <server> <document> [options] =<header> <value> ... <arg> <value> ...\n");
  303 + print(" Options are:\n");
  304 + print(" -print_all print request, response line, headers and document\n");
  305 + print(" (default is to print only the document)\n").
  306 +
  307 +
  308 +
  309 +
  310 + Below is our accept policy function for the command line module. This function may
  311 + serve as a model for your own accept policy function.
  312 +
  313 +public define Bool
  314 + command_line_accept_policy
  315 + (
  316 + Maybe(X509) mbcert
  317 + ) =
  318 + if mbcert is
  319 + {
  320 + failure then
  321 + print("No server certificate or invalid server certificate.\n");
  322 + print("Do you want to trust this site anyway ? [Y/N]\n");
  323 + yes, // this is the same as 'if yes then true else false'
  324 +
  325 + success(cert) then
  326 + print(to_string(cert));
  327 + print("\nDo you want to accept the above certificate ? [Y/N]\n");
  328 + if yes
  329 + then (
  330 + print("Do you want to accept this certificate for ever ? [Y/N]\n");
  331 + if yes
  332 + then (if trust_for_ever(cert) is
  333 + {
  334 + ca_directory_not_found then print("'ca' directory not found.\n"),
  335 + cannot_create_file then print("cannot create file.\n"),
  336 + cannot_create_symbolic_link then print("cannot create symbolic link.\n"),
  337 + write_error then print("write error.\n"),
  338 + ok then unique
  339 + }; true)
  340 + else true
  341 + )
  342 + else false
  343 + }.
  344 +
  345 +
  346 +global define One
  347 + https_get
  348 + (
  349 + List(String) args
  350 + ) =
  351 + if args is
  352 + {
  353 + [ ] then syntax_https_get,
  354 + [server . t] then if t is
  355 + {
  356 + [ ] then syntax_https_get,
  357 + [document . rest] then
  358 + with print_all = member(rest,"-print_all"),
  359 + headers = get_headers(rest),
  360 + arguments = get_arguments(rest),
  361 + if https_get(print_all,server,document,headers,arguments,command_line_accept_policy) is
  362 + {
  363 + cannot_resolve_server_name(dns_error) then
  364 + print("Cannot resolve server name: " + format(dns_error) + ".\n"),
  365 +
  366 + ssl_connect_error(connect_error) then
  367 + print("SSL connect error: " + format(connect_error) + ".\n"),
  368 +
  369 + transmission_problem then
  370 + print("Transmission problem.\n"),
  371 +
  372 + request_refused_by_server then
  373 + print("The request has been refused by server: " + server + ".\n"),
  374 +
  375 + ok(response,headers1,document1) then
  376 + (
  377 + if print_all
  378 + then (
  379 + print("\n----- response ----\n");
  380 + print(response);
  381 + print("\n----- headers -----\n");
  382 + print_headers(headers1);
  383 + print("----- document ----\n")
  384 + ) else unique
  385 + );
  386 + print(document1) // on the screen (use a redirection to get it in a file)
  387 + }
  388 + }
  389 + }.
  390 +
... ...
web/CXM_xml_rpc.anubis 0 → 100644
  1 +/*
  2 + * Created by PyramIDE.
  3 + * User: Totoro
  4 + * Date: 29/06/2013
  5 + * Time: 00:47
  6 + *
  7 + * To change this template use Tools | Options | Coding | Edit Standard Headers.
  8 + */
  9 +
  10 +read tools/base64.anubis
  11 +read tools/basis.anubis
  12 +read tools/connections.anubis
  13 +read system/convert.anubis
  14 +read system/string.anubis
  15 +read web/CXM_common.anubis
  16 +read web/CXM_http_get_common.anubis
  17 +read web/CXM_xml_rpc_parser.anubis
  18 +read web/CXM_xml_rpc_types.anubis
  19 +
  20 +
  21 +define XML_RPC_parameters sysinfo_params =
  22 + parameters
  23 + [
  24 + parameter[int(1)],
  25 + parameter[bool(true)],
  26 + parameter[string("This is a string")],
  27 + parameter[double(1.45)],
  28 + parameter[datetime("date to do")],
  29 + parameter[base64("Base 64 content")],
  30 + parameter[struct(members([
  31 + member("1st member", int(2)),
  32 + member("2nd member", string("this is the 2nd string"))
  33 + ]))],
  34 + parameter[array(array([
  35 + int(3),
  36 + string("3rd string")
  37 + ]))]
  38 + ].
  39 +
  40 +define XML_RPC_parameters empty_param = parameters [].
  41 +
  42 +public type XML_RPC_Result:
  43 + cannot_resolve_server_name(DNS_Result),
  44 + cannot_connect_to_server(NetworkConnectError),
  45 + transmission_problem,
  46 + request_refused_by_server,
  47 + ok(String response, // HTTP response line from the server
  48 + List(HTTP_header) headers, // HTTP headers received from the server
  49 + String document). // The HTML document itself
  50 +
  51 +public type XML_RPC_Auth:
  52 + none,
  53 + basic(String login, String password).
  54 +
  55 +public type XML_RPC_client:
  56 + xml_rpc_client(
  57 + Connection conn,
  58 + XML_RPC_Auth auth,
  59 + String url,
  60 + String user_agent,
  61 + String host).
  62 +
  63 +define String
  64 + tab
  65 + (
  66 + Int position
  67 + )=
  68 + to_string(constant_byte_array(position * 2, ' ')).
  69 +
  70 +define String format_struct(XML_RPC_struct structure, Int position).
  71 +define String format_array(XML_RPC_array array, Int position).
  72 +
  73 +define String format_int_value ( Word32 value) = "<value><i4>"+to_String(value)+"</i4></value>" + crlf.
  74 +define String format_boolean_value ( Bool value) = "<value><boolean>"+to_String_value(value)+"</boolean></value>" + crlf.
  75 +define String format_string_value ( String value) = "<value><string>"+value+"</string></value>" + crlf.
  76 +define String format_double_value ( Float value) = "<value><double>"+float_to_string(value, 10)+"</double></value>" + crlf.
  77 +define String format_datetime_value ( String value) = "<value><dateTime.iso8601>"+value+"</dateTime.iso8601></value>" + crlf.
  78 +define String format_base64_value ( String value) = "<value><base64>"+value+"</base64></value>" + crlf.
  79 +
  80 +define String
  81 + format_value
  82 + (
  83 + XML_RPC_value rpc_value,
  84 + Int position
  85 + )=
  86 + with return = if rpc_value is
  87 + {
  88 + int(value) then format_int_value(value),
  89 + bool(value) then format_boolean_value(value),
  90 + string(value) then format_string_value(value),
  91 + double(value) then format_double_value(value),
  92 + datetime(value) then format_datetime_value(value),
  93 + base64(value) then format_base64_value(value),
  94 + struct(value) then format_struct(value, position + 1),
  95 + array(value) then format_array(value, position + 1)
  96 + },
  97 + tab(position) + return.
  98 +
  99 +
  100 +define String
  101 + _format_struct
  102 + (
  103 + String so_far,
  104 + List(XML_RPC_struct_member) members,
  105 + Int position
  106 + )=
  107 + if members is
  108 + {
  109 + [] then so_far,
  110 + [h . t] then
  111 + if h is member(name, val) then
  112 + _format_struct( so_far + tab(position) + "<member>" + crlf +
  113 + tab(position + 1)+"<name>"+name+"</name>" + crlf +
  114 + format_value(val, position + 1) +
  115 + tab(position + 1) + "</member>" + crlf,
  116 + t,
  117 + position)
  118 + }.
  119 +
  120 +define String
  121 + format_struct
  122 + (
  123 + XML_RPC_struct struct,
  124 + Int position
  125 + ) =
  126 + if struct is members(structure_members) then
  127 + /*tab(position) +*/ "<struct>" + crlf +
  128 + _format_struct("", structure_members, position+1)+
  129 + tab(position + 1) + "</struct>" + crlf.
  130 +
  131 +define String
  132 + _format_array
  133 + (
  134 + String so_far,
  135 + List(XML_RPC_value) values,
  136 + Int position
  137 + )=
  138 + if values is
  139 + {
  140 + [] then so_far,
  141 + [h . t] then _format_array( so_far + format_value(h, position), t, position)
  142 + }.
  143 +
  144 +define String
  145 + format_array
  146 + (
  147 + XML_RPC_array arr,
  148 + Int position
  149 + )
  150 + =
  151 + if arr is array(values) then
  152 + /*tab(position) +*/ "<array>" + crlf +
  153 + tab(position + 1) + "<data>" + crlf+
  154 + _format_array("", values, position + 2)+
  155 + tab(position+2)+"</data>" + crlf +
  156 + tab(position + 1) + "</array>" + crlf.
  157 +
  158 +public define String
  159 + format_xml_rpc_values
  160 + (
  161 + List(XML_RPC_value) values,
  162 + Int position,
  163 + String so_far
  164 + )=
  165 + if values is
  166 + {
  167 + [] then so_far,
  168 + [ h . t ] then
  169 + format_xml_rpc_values(t, position, so_far + format_value(h, position))
  170 + }.
  171 +
  172 +public define String
  173 + format_xml_rpc_parameter
  174 + (
  175 + XML_RPC_parameter param,
  176 + Int position
  177 + )=
  178 + if param is parameter(values) then
  179 + format_xml_rpc_values(values, position, "")
  180 + .
  181 +
  182 +
  183 +define String
  184 + _format_xml_rpc_parameters
  185 + (
  186 + String so_far,
  187 + List(XML_RPC_parameter) params,
  188 + Int position
  189 + )=
  190 + if params is
  191 + {
  192 + [] then so_far,
  193 + [ h . t ] then
  194 + _format_xml_rpc_parameters( so_far + tab(position) + "<param>" + crlf +
  195 + format_xml_rpc_parameter(h, position + 1) +
  196 + tab(position+1) + "</param>" + crlf,
  197 + t,
  198 + position)
  199 + }.
  200 +
  201 +public define String
  202 + format_xml_rpc_parameters
  203 + (
  204 + XML_RPC_parameters params,
  205 + Int position
  206 + )=
  207 + if params is parameters(list_param) then
  208 + tab(position)+"<params>" + crlf +
  209 + _format_xml_rpc_parameters("", list_param, position+1) +
  210 + tab(position+1)+"</params>".
  211 +
  212 +public define String
  213 + format_xml_rpc_fault
  214 + (
  215 + XML_RPC_value value,
  216 + Int position
  217 + )=
  218 + tab(position)+"<fault>" + crlf +
  219 + format_value(value, position+1) +
  220 + tab(position+1)+"</fault>".
  221 +
  222 +public define Bool
  223 + accept_policy
  224 + (
  225 + Maybe(X509) suspect_certificate
  226 + ) = true.
  227 +
  228 +public define Maybe(XML_RPC_client)
  229 + xml_rpc_new_client
  230 + (
  231 + String server_name,
  232 + Bool use_ssl,
  233 + XML_RPC_Auth auth,
  234 + String user_agent,
  235 + String host
  236 + )=
  237 + if separate_name_port(server_name, if use_ssl then 443 else 80) is (name, server_port) then
  238 + //
  239 + // resolve server name and call 'https_get' with numeric server address:
  240 + //
  241 + with a = dns(name),
  242 + if a is ok(server_addr) then
  243 + //connect to server with right protocol
  244 + if use_ssl then
  245 + println("SSL "+server_port+ " "+server_name);
  246 + if open_SSL_connection(server_name, server_addr, server_port, accept_policy) is
  247 + {
  248 + error(msg) then failure,
  249 + ok(conn) then success(xml_rpc_client(ssl(conn), auth, server_name, user_agent, host))
  250 + }
  251 + else
  252 + println("TCP "+server_port+ " "+server_name);
  253 + if (Result(NetworkConnectError,RWStream))connect(server_addr, server_port) is
  254 + {
  255 + error(e) then failure,
  256 + ok(conn) then success(xml_rpc_client(tcp(conn), auth, server_name, user_agent, host))
  257 + }
  258 + else
  259 + failure.
  260 +
  261 +define Maybe(XML_RPC_response)
  262 + receive
  263 + (
  264 + Bool print_dump,
  265 + Connection conn
  266 + )=
  267 + //TODO find the header and content-lenght to get full length of answer
  268 +
  269 + if read(conn, 16384, 5) is
  270 + {
  271 + error then println("Read error");failure,
  272 + timeout then println("Read timeout");failure,
  273 + ok(ba) then
  274 + with xml_response = to_string(ba),
  275 + typed_response = xml_rpc_get_response(xml_response),
  276 + (if print_dump then
  277 +
  278 + println("=== Server answer ==="+crlf + xml_response );
  279 + println("=== XML_RPC Anubis interpretation ===");
  280 +
  281 + if typed_response is
  282 + {
  283 + failure then println("Interpretation error"),
  284 + success(result) then
  285 + if result is
  286 + {
  287 + ok(ok_res) then println(format_xml_rpc_parameters(ok_res,1)),
  288 + fault(fault) then println(format_xml_rpc_fault(fault,1))
  289 + }
  290 +
  291 + }
  292 + else unique);
  293 + typed_response
  294 + }
  295 + .
  296 +
  297 +public define Maybe(XML_RPC_response)
  298 + xml_rpc_client_execute
  299 + (
  300 + Bool print_dump,
  301 + XML_RPC_client client,
  302 + String url,
  303 + String method_name,
  304 + XML_RPC_parameters params
  305 + //(XML-string)->$T answer_handler //convert the xml answer to anubis type
  306 + )=
  307 + if client is xml_rpc_client(conn, auth, server_name, user_agent, host) then
  308 + //execute the method on remote server
  309 + // - 1 - Format the xml body to comply with XML RPC
  310 + with body = "<?xml version=\"1.0\"?>" + crlf +
  311 + tab(1)+"<methodCall>" + crlf +
  312 + tab(2)+"<methodName>" + method_name +"</methodName>" + crlf +
  313 + format_xml_rpc_parameters(params, 2) +
  314 + tab(1)+"</methodCall>",
  315 +
  316 + // - 2 - Format the POST HTTP request
  317 + with request = "POST "+url+" HTTP/1.1"+ crlf + //HTTP/1.1 is very important because it allow to send multiple execute
  318 + "User-Agent: "+ user_agent + crlf + //with only one connection (keep-alive is default in http 1.1)
  319 + "Host: " + server_name + crlf +
  320 + "Content-type: text/xml" + crlf +
  321 + if auth is
  322 + {
  323 + none then "",
  324 + basic(login, pass) then "Authorization: Basic "+base64_encode(login+":"+pass)+ crlf
  325 + }+
  326 + "Content-length: " + length(body)+ crlf +
  327 +
  328 + //format_headers(headers) +
  329 + crlf +
  330 + body,
  331 +
  332 + // - 3 - send it to remote
  333 +
  334 + //
  335 + // Send the HTTP request, and receive the answer:
  336 + //
  337 + (if print_dump then
  338 + (
  339 + print("----- request ----\n");
  340 + print(request);
  341 + print("\n")
  342 + ) else unique);
  343 +
  344 + if write(conn, to_byte_array(request)) is
  345 + {
  346 + failure then failure,
  347 + success(_) then receive(print_dump, conn)
  348 + }.
  349 +
  350 + //wait the answer
  351 +
  352 +
  353 +global define One
  354 + xml_rpc_test
  355 + (
  356 + List(String) args
  357 + )=
  358 + if xml_rpc_new_client("mail.calexium.com:33610", true, basic("admin","the secret passsword"), "Anubis XML-RPC", "127.0.0.1") is
  359 + {
  360 + failure then println(" xml_rpc_test new client failure"),
  361 + success(rpc_client) then
  362 + forget(xml_rpc_client_execute(true, rpc_client, "/Settings", "list_domains", empty_param))
  363 + //forget(xml_rpc_client_execute(true, rpc_client, "/Settings", "delete_domain", parameters([parameter[string("amisdefontainebleau.org")]])))
  364 + //forget(xml_rpc_client_execute(true, rpc_client, "/Settings", "create_domain", empty_param))
  365 + }.
  366 +
... ...
web/CXM_xml_rpc_parser.anubis 0 → 100644
  1 +/*
  2 + * Created by PyramIDE.
  3 + * User: Totoro
  4 + * Date: 06/07/2013
  5 + * Time: 01:13
  6 + *
  7 + * To change this template use Tools | Options | Coding | Edit Standard Headers.
  8 + */
  9 +
  10 +read web/CXM_xml_rpc_types.anubis
  11 +read tools/streams.anubis
  12 +read tools/basis.anubis
  13 +read system/string.anubis
  14 +read system/convert.anubis
  15 +
  16 +type XML_RPC_Token:
  17 + none,
  18 + token(String token).
  19 +
  20 +define Maybe(XML_RPC_value) read_value(Stream stream).
  21 +
  22 +define XML_RPC_Token
  23 + _next_xml_token
  24 + (
  25 + Stream stream,
  26 + List(Word8) so_far,
  27 + Bool in_token
  28 + )=
  29 + if read_byte(stream) is
  30 + {
  31 + failure then none, //can't read on stream !!
  32 + success(b) then
  33 + //println("["+implode([b])+"]");
  34 + if in_token then
  35 + if b = '>' then //just found the end of bracket, so we return the token in LOWER case
  36 + with tok = to_lower(implode(reverse(so_far))),
  37 + //println("found tag "+tok);
  38 + token(tok)
  39 + else
  40 + _next_xml_token(stream, [b . so_far], in_token)
  41 + else
  42 + if b = '<' then //just found the begin of token
  43 + _next_xml_token(stream, [], true)
  44 + else
  45 + _next_xml_token(stream, so_far, in_token)
  46 + }
  47 + .
  48 +
  49 +
  50 +
  51 +define XML_RPC_Token
  52 + next_xml_token
  53 + (
  54 + Stream stream
  55 + )= _next_xml_token(stream, [], false).
  56 +
  57 +define Maybe(String)
  58 + _xml_tag_content
  59 + (
  60 + Stream stream,
  61 + String tag, //tag to match
  62 + List(Word8) so_far,
  63 + List(Word8) content,
  64 + Bool in_first_token,
  65 + Bool in_content,
  66 + Bool in_last_token
  67 +
  68 + )=
  69 + if read_byte(stream) is
  70 + {
  71 + failure then failure, //can't read on stream !!
  72 + success(b) then
  73 + if in_first_token then
  74 + if b = '>' then //just found the end of bracket, so we return the token in LOWER case
  75 + if to_lower(implode(reverse(so_far))) = tag then
  76 + _xml_tag_content(stream, tag, [], [], false, true, false)
  77 + else
  78 + failure
  79 + else
  80 + _xml_tag_content(stream, tag, [b . so_far], content, in_first_token, in_content, in_last_token)
  81 + else if in_content then
  82 + if b = '<' then //just found the begin bracket,
  83 + if read_byte(stream) is
  84 + {
  85 + failure then failure, //can't read on stream !!
  86 + success(b) then
  87 + if b = '/' then //can't find / => syntax error
  88 + _xml_tag_content(stream, tag, [], content, false, false, true)
  89 + else
  90 + failure
  91 + }
  92 + else
  93 + _xml_tag_content(stream, tag, [], [b . content], false, true, false)
  94 + else if in_last_token then
  95 + if b = '>' then //just found the end of bracket, so we return the token in LOWER case
  96 + if to_lower(implode(reverse(so_far))) = tag then
  97 + with content = implode(reverse(content)),
  98 + println("Tag ["+tag+"] content found ["+content+"]");
  99 + success(content)
  100 + else
  101 + failure
  102 + else
  103 + _xml_tag_content(stream, tag, [b . so_far], content, false, false, true)
  104 +
  105 + else
  106 + if b = '<' then //just found the begin of token
  107 + _xml_tag_content(stream, tag, [], [], true, false, false)
  108 + else
  109 + _xml_tag_content(stream, tag, [], [], false, false, false)
  110 + }
  111 + .
  112 +define Maybe(String)
  113 + xml_pair_tag_content
  114 + (
  115 + Stream stream,
  116 + String tag
  117 + )= _xml_tag_content( stream, tag, [], [], false, false, false).
  118 +
  119 +define Maybe(String)
  120 + xml_tag_content
  121 + (
  122 + Stream stream,
  123 + String tag
  124 + )= _xml_tag_content( stream, tag, [], [], false, true, false).
  125 +
  126 + /***** ARRAY functions ******/
  127 +
  128 +define Maybe(List(XML_RPC_value))
  129 + read_values
  130 + (
  131 + Stream stream,
  132 + List(XML_RPC_value) so_far
  133 + )=
  134 + if read_value(stream) is
  135 + {
  136 + failure then failure,
  137 + success(value) then
  138 + if next_xml_token(stream) is
  139 + {
  140 + none then failure,
  141 + token(token) then
  142 +
  143 + if token = "value" then //there is another value we read it
  144 + read_values(stream, [value . so_far])
  145 + else
  146 + unput_string("<"+token+">", stream);
  147 + success(reverse([value . so_far]))
  148 + }
  149 + }.
  150 +
  151 +define Maybe(List(XML_RPC_value))
  152 + read_data
  153 + (
  154 + Stream stream
  155 + )=
  156 + if next_xml_token(stream) is
  157 + {
  158 + none then failure,
  159 + token(token) then
  160 + if token = "data" then
  161 + if next_xml_token(stream) is
  162 + {
  163 + none then failure,
  164 + token(token) then
  165 + if token = "value" then
  166 + if read_values(stream, []) is
  167 + {
  168 + failure then failure
  169 + success(values) then
  170 + if next_xml_token(stream) is
  171 + {
  172 + none then failure,
  173 + token(token) then
  174 + if token = "/data" then
  175 + success(values)
  176 + else
  177 + failure
  178 + }
  179 + }
  180 + else
  181 + failure
  182 + }
  183 + else
  184 + failure
  185 + }.
  186 +
  187 +define Maybe(XML_RPC_value)
  188 + read_array
  189 + (
  190 + Stream stream
  191 + )=
  192 + if read_data(stream) is
  193 + {
  194 + failure then failure
  195 + success(values) then
  196 + if next_xml_token(stream) is
  197 + {
  198 + none then failure,
  199 + token(token) then
  200 + if token = "/array" then
  201 + success(array(array(values)))
  202 + else
  203 + failure
  204 + }
  205 + }.
  206 +
  207 + /***** STRUCT functions ******/
  208 +
  209 +define Maybe(List(XML_RPC_struct_member))
  210 + read_members
  211 + (
  212 + Stream stream,
  213 + List(XML_RPC_struct_member) so_far
  214 + )=
  215 + if xml_pair_tag_content(stream, "name") is
  216 + {
  217 + failure then failure,
  218 + success(member_name) then
  219 + if next_xml_token(stream) is
  220 + {
  221 + none then failure,
  222 + token(tok) then
  223 + if tok = "value" then
  224 + if read_value(stream) is
  225 + {
  226 + failure then failure,
  227 + success(value) then
  228 + if next_xml_token(stream) is
  229 + {
  230 + none then failure,
  231 + token(tok) then
  232 + if tok = "/member" then
  233 + if next_xml_token(stream) is
  234 + {
  235 + none then failure,
  236 + token(tok) then
  237 + if tok = "member" then //there is another member in structure, we read it
  238 + read_members(stream, [member(member_name, value) . so_far])
  239 + else if tok = "/struct" then //End of structrue found
  240 + println("End struct");
  241 + success(reverse([member(member_name, value) . so_far])) //return all members in right order
  242 + else
  243 + failure //unexpected token
  244 + }
  245 + else
  246 + failure
  247 + }
  248 + }
  249 + else
  250 + failure
  251 + }
  252 + } .
  253 +
  254 +define Maybe(XML_RPC_value)
  255 + read_struct
  256 + (
  257 + Stream stream
  258 + )=
  259 + if next_xml_token(stream) is
  260 + {
  261 + none then failure,
  262 + token(token) then
  263 + if token = "member" then
  264 + if read_members(stream, []) is
  265 + {
  266 + failure then failure
  267 + success(members_list) then success(struct(members(members_list)))
  268 + }
  269 + else
  270 + failure
  271 + }.
  272 +
  273 +define Maybe(XML_RPC_value)
  274 + read_value
  275 + (
  276 + Stream stream
  277 + )=
  278 + if next_xml_token(stream) is
  279 + {
  280 + none then failure,
  281 + token(token) then
  282 + with value = if token = "string" then
  283 + if xml_tag_content(stream, "string") is
  284 + {
  285 + failure then failure,
  286 + success(v) then success(string(v))
  287 + }
  288 + else if token = "int" then
  289 + if xml_tag_content(stream, "int") is
  290 + {
  291 + failure then failure,
  292 + success(v) then
  293 + if decimal_scan(v) is
  294 + {
  295 + failure then failure,
  296 + success(int_v) then success(int(truncate_to_Word32(int_v)))
  297 + }
  298 + }
  299 + else if token = "i4" then
  300 + if xml_tag_content(stream, "i4") is
  301 + {
  302 + failure then failure,
  303 + success(v) then
  304 + if decimal_scan(v) is
  305 + {
  306 + failure then failure,
  307 + success(int_v) then success(int(truncate_to_Word32(int_v)))
  308 + }
  309 + }
  310 + else if token = "boolean" then
  311 + if xml_tag_content(stream, "boolean") is
  312 + {
  313 + failure then failure,
  314 + success(v) then success(bool(to_Bool(v)))
  315 + }
  316 + else if token = "double" then
  317 + if xml_tag_content(stream, "string") is
  318 + {
  319 + failure then failure,
  320 + success(v) then success(double(0.0))
  321 + }
  322 + else if token = "datetime" then
  323 + if xml_tag_content(stream, "string") is
  324 + {
  325 + failure then failure,
  326 + success(v) then success(datetime(v))
  327 + }
  328 + else if token = "base64" then
  329 + if xml_tag_content(stream, "base64") is
  330 + {
  331 + failure then failure,
  332 + success(b64) then success(base64(b64))
  333 + }
  334 + else if token = "struct" then read_struct(stream)
  335 + else if token = "array" then read_array(stream)
  336 + else
  337 + failure,
  338 + if next_xml_token(stream) is
  339 + {
  340 + none then failure
  341 + token(token) then
  342 + if token = "/value" then
  343 + value
  344 + else
  345 + failure
  346 + }
  347 + }.
  348 +
  349 +define Maybe(XML_RPC_parameter)
  350 + in_value
  351 + (
  352 + Stream stream,
  353 + List(XML_RPC_value) so_far
  354 + )=
  355 + if next_xml_token(stream) is
  356 + {
  357 + none then failure,
  358 + token(tok) then
  359 + if tok = "value" then
  360 + if read_value(stream) is
  361 + {
  362 + failure then failure,
  363 + success(value) then in_value(stream, [ value. so_far])
  364 + }
  365 + else if tok = "/param" then
  366 + success(parameter(reverse(so_far)))
  367 + else
  368 + failure
  369 + }.
  370 +
  371 +define Maybe(XML_RPC_value)
  372 + in_fault
  373 + (
  374 + Stream stream,
  375 + )=
  376 + if next_xml_token(stream) is
  377 + {
  378 + none then failure,
  379 + token(tok) then
  380 + if tok = "value" then
  381 + if read_value(stream) is
  382 + {
  383 + failure then failure,
  384 + success(value) then
  385 + if next_xml_token(stream) is
  386 + {
  387 + none then failure,
  388 + token(tok) then
  389 + if tok = "/fault" then
  390 + success(value)
  391 + else
  392 + failure
  393 + }
  394 + }
  395 + else
  396 + failure
  397 + }.
  398 +
  399 +define Maybe(XML_RPC_parameters)
  400 + in_param
  401 + (
  402 + Stream stream,
  403 + List(XML_RPC_parameter) so_far
  404 + )=
  405 + if next_xml_token(stream) is
  406 + {
  407 + none then failure,
  408 + token(tok) then
  409 + if tok = "param" then
  410 + if in_value(stream, []) is
  411 + {
  412 + failure then failure,
  413 + success(param) then in_param(stream, [ param . so_far])
  414 + }
  415 +
  416 + else if tok = "/params" then
  417 + success(parameters(reverse(so_far)))
  418 + else
  419 + failure
  420 + }
  421 + .
  422 +
  423 +define Maybe(XML_RPC_response)
  424 + in_params
  425 + (
  426 + Stream stream
  427 + )=
  428 + if next_xml_token(stream) is
  429 + {
  430 + none then failure,
  431 + token(tok) then
  432 + if tok = "params" then
  433 + if in_param(stream, []) is
  434 + {
  435 + failure then failure,
  436 + success(resp) then success(ok(resp))
  437 + }
  438 + else if tok = "fault" then
  439 + if in_fault(stream) is
  440 + {
  441 + failure then failure,
  442 + success(resp) then success(fault(resp))
  443 + }
  444 + else
  445 + failure
  446 + }
  447 +
  448 + .
  449 +
  450 +public define Maybe(XML_RPC_response)
  451 + xml_rpc_get_response
  452 + (
  453 + String response
  454 + )=
  455 + with stream = make_stream(response),
  456 + if next_xml_token(stream) is
  457 + {
  458 + none then failure
  459 + token(tok) then
  460 + if tok = "?xml version='1.0'?" then
  461 + if next_xml_token(stream) is
  462 + {
  463 + none then failure
  464 + token(tok) then
  465 + if tok = "methodresponse" then
  466 + in_params(stream)
  467 + else
  468 + failure
  469 + }
  470 + else
  471 + failure
  472 + }.
... ...
web/CXM_xml_rpc_types.anubis 0 → 100644
  1 +/*
  2 + * Created by PyramIDE.
  3 + * User: Totoro
  4 + * Date: 06/07/2013
  5 + * Time: 15:27
  6 + *
  7 + * To change this template use Tools | Options | Coding | Edit Standard Headers.
  8 + */
  9 +
  10 +public type XML_RPC_struct:...
  11 +public type XML_RPC_array:...
  12 +
  13 +public type XML_RPC_value:
  14 + int(Word32),
  15 + bool(Bool),
  16 + string(String),
  17 + double(Float),
  18 + datetime(String),
  19 + base64(String),
  20 + struct(XML_RPC_struct),
  21 + array(XML_RPC_array).
  22 +
  23 +public type XML_RPC_array:
  24 + array(List(XML_RPC_value)).
  25 +
  26 +public type XML_RPC_struct_member:
  27 + member(String name, XML_RPC_value value).
  28 +
  29 +public type XML_RPC_struct:
  30 + members(List(XML_RPC_struct_member)).
  31 +
  32 +public type XML_RPC_parameter:
  33 + parameter(List(XML_RPC_value)).
  34 +
  35 +public type XML_RPC_parameters:
  36 + parameters(List(XML_RPC_parameter)).
  37 +
  38 +public type XML_RPC_response:
  39 + ok(XML_RPC_parameters params),
  40 + fault(XML_RPC_value fault).
  41 +
... ...