diff options
author | ariel- <ariel-@users.noreply.github.com> | 2017-07-19 12:51:28 -0300 |
---|---|---|
committer | Aokromes <aokromes@gmail.com> | 2017-07-20 11:26:26 +0200 |
commit | f7e7aef8fcd057d3f23a83da8bec48abaf36779e (patch) | |
tree | ab216ac10d5383bd7a6687982d1e89ca87cb1e19 /dep/gsoap/stdsoap2.cpp | |
parent | a9174d5eb75b4e0f28542c44b797fcacddc7ab64 (diff) |
Dep/gSOAP: Update gSOAP to 2.8.49
Closes #20039
Diffstat (limited to 'dep/gsoap/stdsoap2.cpp')
-rw-r--r-- | dep/gsoap/stdsoap2.cpp | 2786 |
1 files changed, 1978 insertions, 808 deletions
diff --git a/dep/gsoap/stdsoap2.cpp b/dep/gsoap/stdsoap2.cpp index bec1d4b02a5..2447a2b2d6a 100644 --- a/dep/gsoap/stdsoap2.cpp +++ b/dep/gsoap/stdsoap2.cpp @@ -1,17 +1,18 @@ /* - stdsoap2.c[pp] 2.8.33 + stdsoap2.c[pp] 2.8.49 gSOAP runtime engine gSOAP XML Web services tools -Copyright (C) 2000-2016, Robert van Engelen, Genivia Inc., All Rights Reserved. +Copyright (C) 2000-2017, Robert van Engelen, Genivia Inc., All Rights Reserved. This part of the software is released under ONE of the following licenses: GPL, or the gSOAP public license, or Genivia's license for commercial use. -------------------------------------------------------------------------------- Contributors: -Wind River Systems Inc., for the following additions under gSOAP public license: - - vxWorks compatible options +Wind River Systems, Inc., for the following addition licensed under the gSOAP +public license: + - vxWorks compatible, enabled with compiler option -DVXWORKS -------------------------------------------------------------------------------- gSOAP public license. @@ -24,7 +25,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Robert A. van Engelen. -Copyright (C) 2000-2016, Robert van Engelen, Genivia Inc., All Rights Reserved. +Copyright (C) 2000-2017, Robert van Engelen, Genivia Inc., All Rights Reserved. -------------------------------------------------------------------------------- GPL license. @@ -51,12 +52,16 @@ A commercial use license is available from Genivia, Inc., contact@genivia.com -------------------------------------------------------------------------------- */ -#define GSOAP_LIB_VERSION 20833 +#define GSOAP_LIB_VERSION 20849 #ifdef AS400 # pragma convert(819) /* EBCDIC to ASCII */ #endif +#if defined(__gnu_linux__) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE 1 +#endif + #include "stdsoap2.h" #if GSOAP_VERSION != GSOAP_LIB_VERSION @@ -64,7 +69,7 @@ A commercial use license is available from Genivia, Inc., contact@genivia.com #endif #if defined(VXWORKS) && defined(WM_SECURE_KEY_STORAGE) -# include <ipcom_key_db.h> +# include <ipcom_key_db.h> /* vxWorks compatible */ #endif #ifdef __BORLANDC__ @@ -81,10 +86,10 @@ A commercial use license is available from Genivia, Inc., contact@genivia.com #endif #ifdef __cplusplus -SOAP_SOURCE_STAMP("@(#) stdsoap2.cpp ver 2.8.33 2016-06-14 00:00:00 GMT") +SOAP_SOURCE_STAMP("@(#) stdsoap2.cpp ver 2.8.49 2017-07-10 00:00:00 GMT") extern "C" { #else -SOAP_SOURCE_STAMP("@(#) stdsoap2.c ver 2.8.32 2016-06-14 00:00:00 GMT") +SOAP_SOURCE_STAMP("@(#) stdsoap2.c ver 2.8.49 2017-07-10 00:00:00 GMT") #endif /* 8bit character representing unknown character entity or multibyte data */ @@ -106,8 +111,7 @@ SOAP_SOURCE_STAMP("@(#) stdsoap2.c ver 2.8.32 2016-06-14 00:00:00 GMT") #define SOAP_QT (soap_wchar)(-5) /* XML-specific '"' */ #define SOAP_AP (soap_wchar)(-6) /* XML-specific ''' */ -#define soap_blank(c) ((c)+1 > 0 && (c) <= 32) -#define soap_notblank(c) ((c) > 32) +#define soap_coblank(c) ((c)+1 > 0 && (c) <= 32) #if defined(WIN32) && !defined(UNDER_CE) #define soap_hash_ptr(p) ((PtrToUlong(p) >> 3) & (SOAP_PTRHASH - 1)) @@ -136,12 +140,13 @@ static int soap_getattrval(struct soap*, char*, size_t*, soap_wchar); #endif #ifndef PALM_1 -static void soap_free_ns(struct soap *soap); +static void soap_version(struct soap*); +static void soap_free_ns(struct soap*); static soap_wchar soap_char(struct soap*); -static soap_wchar soap_get_pi(struct soap*); +static soap_wchar soap_getpi(struct soap*); static int soap_isxdigit(int); static void *fplugin(struct soap*, const char*); -static size_t soap_count_attachments(struct soap *soap); +static size_t soap_count_attachments(struct soap*); static int soap_try_connect_command(struct soap*, int http_command, const char *endpoint, const char *action); #ifdef WITH_NTLM static int soap_ntlm_handshake(struct soap *soap, int command, const char *endpoint, const char *host, int port); @@ -160,19 +165,21 @@ static void soap_free_pht(struct soap*); #ifndef WITH_LEAN static const char *soap_set_validation_fault(struct soap*, const char*, const char*); static int soap_isnumeric(struct soap*, const char*); -static struct soap_nlist *soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized); -static void soap_utilize_ns(struct soap *soap, const char *tag); -static const wchar_t* soap_wstring(struct soap *soap, const char *s, long minlen, long maxlen, const char *pattern); +static struct soap_nlist *soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized, short isearly); +static void soap_utilize_ns(struct soap *soap, const char *tag, short isearly); +static const wchar_t* soap_wstring(struct soap *soap, const char *s, int flag, long minlen, long maxlen, const char *pattern); +static wchar_t* soap_wcollapse(struct soap *soap, wchar_t *s, int flag, int insitu); #endif #ifndef PALM_2 -static const char* soap_string(struct soap *soap, const char *s, long minlen, long maxlen, const char *pattern); +static const char* soap_string(struct soap *soap, const char *s, int flag, long minlen, long maxlen, const char *pattern); +static char* soap_collapse(struct soap *soap, char *s, int flag, int insitu); static const char* soap_QName(struct soap *soap, const char *s, long minlen, long maxlen, const char *pattern); #endif #ifndef WITH_LEANER #ifndef PALM_1 -static struct soap_multipart *soap_new_multipart(struct soap*, struct soap_multipart**, struct soap_multipart**, char*, size_t); +static struct soap_multipart *soap_alloc_multipart(struct soap*, struct soap_multipart**, struct soap_multipart**, char*, size_t); static int soap_putdimefield(struct soap*, const char*, size_t); static char *soap_getdimefield(struct soap*, size_t); static void soap_select_mime_boundary(struct soap*); @@ -562,12 +569,12 @@ static int fsend(struct soap *soap, const char *s, size_t n) { int nwritten, err; SOAP_SOCKET sk; + soap->errnum = 0; #if defined(__cplusplus) && !defined(WITH_COMPAT) if (soap->os) { soap->os->write(s, (std::streamsize)n); if (soap->os->good()) return SOAP_OK; - soap->errnum = 0; return SOAP_EOF; } #endif @@ -576,8 +583,7 @@ fsend(struct soap *soap, const char *s, size_t n) sk = soap->socket; while (n) { if (soap_valid_socket(sk)) - { - if (soap->send_timeout) + { if (soap->send_timeout) { for (;;) { int r; #ifdef WITH_OPENSSL @@ -607,6 +613,14 @@ fsend(struct soap *soap, const char *s, size_t n) return SOAP_EOF; } } +#ifndef WITH_LEAN + if (soap->transfer_timeout) + { time_t now = time(NULL); + if ((soap->transfer_timeout > 0 && difftime(now, soap->start) > (double)soap->transfer_timeout) + || (soap->transfer_timeout < 0 && difftime(now, soap->start) > -1000000.0 * (double)soap->transfer_timeout)) + return SOAP_EOF; + } +#endif #ifdef WITH_OPENSSL if (soap->ssl) nwritten = SSL_write(soap->ssl, s, (int)n); @@ -671,8 +685,7 @@ fsend(struct soap *soap, const char *s, size_t n) nwritten = send(sk, (void*)s, n, soap->socket_flags); #endif if (nwritten <= 0) - { - int r = 0; + { int r = 0; err = soap_socket_errno(sk); #ifdef WITH_OPENSSL if (soap->ssl && (r = SSL_get_error(soap->ssl, nwritten)) != SSL_ERROR_NONE && r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) @@ -721,14 +734,12 @@ fsend(struct soap *soap, const char *s, size_t n) #ifdef UNDER_CE nwritten = fwrite(s, 1, n, soap->sendfd); #else -#ifdef VXWORKS #ifdef WMW_RPM_IO + /* vxWorks compatible */ if (soap->rpmreqid) nwritten = (httpBlockPut(soap->rpmreqid, (char*)s, n) == 0) ? n : -1; else #endif - nwritten = fwrite(s, sizeof(char), n, fdopen(soap->sendfd, "w")); -#else #ifdef WIN32 nwritten = _write(soap->sendfd, s, (unsigned int)n); #else @@ -736,7 +747,6 @@ fsend(struct soap *soap, const char *s, size_t n) #endif #endif #endif -#endif if (nwritten <= 0) { #ifndef WITH_FASTCGI @@ -775,7 +785,8 @@ soap_send_raw(struct soap *soap, const char *s, size_t n) return soap->error; #endif if ((soap->mode & SOAP_IO_LENGTH)) - soap->count += n; + { soap->count += n; + } else if (soap->mode & SOAP_IO) { size_t i = sizeof(soap->buf) - soap->bufidx; while (n >= i) @@ -869,7 +880,7 @@ soap_flush_raw(struct soap *soap, const char *s, size_t n) soap->chunksize += n; } DBGMSG(SENT, s, n); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Send %u bytes to socket=%d/fd=%d\n", (unsigned int)n, soap->socket, soap->sendfd)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Send %u bytes to socket=%d/fd=%d\n", (unsigned int)n, (int)soap->socket, soap->sendfd)); #endif return soap->error = soap->fsend(soap, s, n); } @@ -921,6 +932,36 @@ soap_send3(struct soap *soap, const char *s1, const char *s2, const char *s3) /******************************************************************************/ +#ifndef WITH_LEANER +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_send_key(struct soap *soap, const char *s) +{ if (!soap->body && soap_send_raw(soap, "&", 1)) + return soap->error; + soap->body = 0; + return soap_send(soap, s); +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_LEANER +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_send_val(struct soap *soap, const char *s) +{ soap_encode_url(s, soap->msgbuf, sizeof(soap->msgbuf)); + return soap_send(soap, soap->msgbuf); +} +#endif +#endif + +/******************************************************************************/ + #ifndef WITH_NOIO #ifndef PALM_1 static size_t @@ -932,7 +973,7 @@ frecv(struct soap *soap, char *s, size_t n) #if defined(__cplusplus) && !defined(WITH_COMPAT) if (soap->is) /* recv from C++ stream */ { if (soap->is->good()) - return (size_t)soap->is->read(s, (std::streamsize)n).gcount(); + return (size_t)soap->is->read(s, (std::streamsize)n).gcount(); /* downcast to std::streamsize is OK: gcount() returns how much we got in s[] */ return 0; } #else @@ -970,6 +1011,14 @@ frecv(struct soap *soap, char *s, size_t n) return 0; } } +#ifndef WITH_LEAN + if (soap->transfer_timeout) + { time_t now = time(NULL); + if ((soap->transfer_timeout > 0 && difftime(now, soap->start) > (double)soap->transfer_timeout) + || (soap->transfer_timeout < 0 && difftime(now, soap->start) > -1000000.0 * (double)soap->transfer_timeout)) + return 0; + } +#endif #ifdef WITH_OPENSSL if (soap->ssl) { r = SSL_read(soap->ssl, s, (int)n); @@ -1010,7 +1059,7 @@ frecv(struct soap *soap, char *s, size_t n) if ((soap->omode & SOAP_IO_UDP)) { SOAP_SOCKLEN_T k = (SOAP_SOCKLEN_T)sizeof(soap->peer); memset((void*)&soap->peer, 0, sizeof(soap->peer)); - r = recvfrom(sk, s, (SOAP_WINSOCKINT)n, soap->socket_flags, &soap->peer.addr, &k); /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h */ + r = recvfrom(sk, s, (SOAP_WINSOCKINT)n, soap->socket_flags, &soap->peer.addr, &k); /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h, SOAP_WINSOCKINT cast is safe due to limited range of n in the engine (64K) */ soap->peerlen = (size_t)k; #ifndef WITH_IPV6 soap->ip = ntohl(soap->peer.in.sin_addr.s_addr); @@ -1018,7 +1067,7 @@ frecv(struct soap *soap, char *s, size_t n) } else #endif - r = recv(sk, s, (SOAP_WINSOCKINT)n, soap->socket_flags); + r = recv(sk, s, (SOAP_WINSOCKINT)n, soap->socket_flags); /* SOAP_WINSOCKINT cast is safe due to limited range of n in the engine (64K) */ #ifdef PALM /* CycleSyncDisplay(curStatusMsg); */ #endif @@ -1055,7 +1104,7 @@ frecv(struct soap *soap, char *s, size_t n) return 0; #ifdef PALM r = soap_socket_errno(sk); - if (r != SOAP_EINTR && retries-- <= 0) + if (r != SOAP_EINTR) { soap->errnum = r; return 0; } @@ -1098,7 +1147,7 @@ soap_getchunkchar(struct soap *soap) return soap->buf[soap->bufidx++]; soap->bufidx = 0; soap->buflen = soap->chunkbuflen = soap->frecv(soap, soap->buf, sizeof(soap->buf)); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes from socket=%d/fd=%d\n", (unsigned int)soap->buflen, soap->socket, soap->recvfd)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes from socket=%d/fd=%d\n", (unsigned int)soap->buflen, (int)soap->socket, soap->recvfd)); DBGMSG(RECV, soap->buf, soap->buflen); if (soap->buflen) return soap->buf[soap->bufidx++]; @@ -1196,7 +1245,7 @@ zlib_again: t = tmp; if (!soap->chunkbuflen) { soap->chunkbuflen = ret = soap->frecv(soap, soap->buf, sizeof(soap->buf)); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes (chunked) from socket=%d\n", (unsigned int)ret, soap->socket)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes (chunked) from socket=%d\n", (unsigned int)ret, (int)soap->socket)); DBGMSG(RECV, soap->buf, ret); soap->bufidx = 0; if (!ret) @@ -1215,8 +1264,8 @@ zlib_again: } } do - *t++ = (char)c; - while (soap_isxdigit((int)(c = soap_getchunkchar(soap))) && (size_t)(t - tmp) < sizeof(tmp)-1); + { *t++ = (char)c; + } while (soap_isxdigit((int)(c = soap_getchunkchar(soap))) && (size_t)(t - tmp) < sizeof(tmp)-1); while ((int)c != EOF && c != '\n') c = soap_getchunkchar(soap); if ((int)c == EOF) @@ -1252,7 +1301,7 @@ zlib_again: #endif { soap->bufidx = 0; soap->buflen = ret = soap->frecv(soap, soap->buf, sizeof(soap->buf)); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes from socket=%d/fd=%d\n", (unsigned int)ret, soap->socket, soap->recvfd)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes from socket=%d/fd=%d\n", (unsigned int)ret, (int)soap->socket, soap->recvfd)); DBGMSG(RECV, soap->buf, ret); } #ifdef WITH_ZLIB @@ -1384,26 +1433,44 @@ soap_recv(struct soap *soap) return SOAP_OK; } } - while (soap->ffilterrecv) + if (soap->ffilterrecv) { int err; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filter recverror = %d\n", soap->recverror)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filter recverror = %d bufidx = %lu buflen = %lu\n", soap->recverror, (unsigned long)soap->bufidx, (unsigned long)soap->buflen)); if (soap->recverror) soap->bufidx = soap->buflen = 0; else - { soap->recverror = soap_recv_raw(soap); /* do not call again after EOF */ + { soap->bufidx = soap->buflen = 0; + err = soap->ffilterrecv(soap, soap->buf, &soap->buflen, sizeof(soap->buf)); + if (err) + { if (err == SOAP_EOF) + return SOAP_EOF; + return soap->error = err; + } + if (soap->buflen) + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filtered output continued %lu bytes\n", (unsigned long)soap->buflen)); + return SOAP_OK; + } + soap->recverror = soap_recv_raw(soap); soap->buflen -= soap->bufidx; /* chunked may set bufidx > 0 to skip hex chunk length */ } - err = soap->ffilterrecv(soap, soap->buf + soap->bufidx, &soap->buflen, sizeof(soap->buf) - soap->bufidx); - if (err) - return soap->error = err; - if (soap->buflen) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filtered %lu\n", (unsigned long)soap->buflen)); - soap->buflen += soap->bufidx; - return SOAP_OK; - } - if (soap->recverror) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Returning postponed EOF%d\n", soap->recverror)); - return soap->recverror; + while (soap->ffilterrecv) + { err = soap->ffilterrecv(soap, soap->buf + soap->bufidx, &soap->buflen, sizeof(soap->buf) - soap->bufidx); + if (err) + { if (err == SOAP_EOF) + return SOAP_EOF; + return soap->error = err; + } + if (soap->buflen) + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filtered output %lu bytes\n", (unsigned long)soap->buflen)); + soap->buflen += soap->bufidx; + return SOAP_OK; + } + if (soap->recverror) + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Returning postponed error %d\n", soap->recverror)); + return soap->recverror; + } + soap->recverror = soap_recv_raw(soap); + soap->buflen -= soap->bufidx; /* chunked may set bufidx > 0 to skip hex chunk length */ } } return soap->recverror = soap_recv_raw(soap); @@ -1495,7 +1562,7 @@ soap_code_bits(const struct soap_code_map *code_map, const char *str) { const struct soap_code_map *p; for (p = code_map; p->string; p++) { size_t n = strlen(p->string); - if (!strncmp(p->string, str, n) && soap_blank((soap_wchar)str[n])) + if (!strncmp(p->string, str, n) && soap_coblank((soap_wchar)str[n])) { bits |= p->code; str += n; while (*str > 0 && *str <= 32) @@ -1644,15 +1711,17 @@ soap_get(struct soap *soap) } switch (c) { case '<': - do c = soap_get1(soap); - while (soap_blank(c)); + do + { c = soap_get1(soap); + } while (soap_coblank(c)); if (c == '!' || c == '?' || c == '%') { int k = 1; if (c == '!') { c = soap_get1(soap); if (c == '[') - { do c = soap_get1(soap); - while ((int)c != EOF && c != '['); + { do + { c = soap_get1(soap); + } while ((int)c != EOF && c != '['); if ((int)c == EOF) break; soap->cdata = 1; @@ -1668,7 +1737,7 @@ soap_get(struct soap *soap) } } else if (c == '?') - c = soap_get_pi(soap); + c = soap_getpi(soap); while ((int)c != EOF) { if (c == '<') k++; @@ -1706,20 +1775,19 @@ soap_get(struct soap *soap) #ifndef PALM_1 static soap_wchar -soap_get_pi(struct soap *soap) +soap_getpi(struct soap *soap) { char buf[64]; char *s = buf; - int i = sizeof(buf); - soap_wchar c = soap_getchar(soap); - /* This is a quick way to parse XML PI and we could use a callback instead to - * enable applications to intercept processing instructions */ - while ((int)c != EOF && c != '?') - { if (--i > 0) - { if (soap_blank(c)) + size_t i = sizeof(buf); + soap_wchar c; + /* Parse the XML PI encoding declaration and look for <?xml ... encoding=X ?> */ + while ((int)(c = soap_getchar(soap)) != EOF && c != '?') + { if (i > 1) + { if (soap_coblank(c)) c = ' '; *s++ = (char)c; + i--; } - c = soap_getchar(soap); } *s = '\0'; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "XML PI <?%s?>\n", buf)); @@ -1830,17 +1898,47 @@ SOAP_FMAC1 soap_wchar SOAP_FMAC2 soap_getutf8(struct soap *soap) -{ soap_wchar c, c1, c2, c3, c4; +{ +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + soap_wchar c, c1, c2, c3; +#else + soap_wchar c, c1, c2, c3, c4; +#endif c = soap->ahead; if (c >= 0x80) soap->ahead = 0; else - c = soap_get(soap); + c = (soap_wchar)soap_get(soap); if (c < 0x80 || c > 0xFF || (soap->mode & SOAP_ENC_LATIN)) return c; - c1 = soap_get1(soap); - if (c1 < 0x80) - { soap_revget1(soap); /* doesn't look like this is UTF8 */ +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + c1 = (soap_wchar)soap_get1(soap); + if (c <= 0xC1 || (c1 & 0xC0) != 0x80) + { soap_revget1(soap); + return SOAP_UNKNOWN_UNICODE_CHAR; + } + c1 &= 0x3F; + if (c < 0xE0) + return (((c & 0x1F) << 6) | c1); + c2 = (soap_wchar)soap_get1(soap); + if ((c == 0xE0 && c1 < 0x20) || (c2 & 0xC0) != 0x80) + { soap_revget1(soap); + return SOAP_UNKNOWN_UNICODE_CHAR; + } + c2 &= 0x3F; + if (c < 0xF0) + return (((c & 0x0F) << 12) | (c1 << 6) | c2); + c3 = (soap_wchar)soap_get1(soap); + if ((c == 0xF0 && c1 < 0x10) || (c == 0xF4 && c1 >= 0x10) || c >= 0xF5 || (c3 & 0xC0) != 0x80) + { soap_revget1(soap); + return SOAP_UNKNOWN_UNICODE_CHAR; + } + return (((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | (c3 & 0x3F)); +#else + c1 = (soap_wchar)soap_get1(soap); + if (c < 0xC0 || (c1 & 0xC0) != 0x80) + { soap_revget1(soap); + /* doesn't look like this is UTF-8, try continue as if ISO-8859-1 */ return c; } c1 &= 0x3F; @@ -1856,6 +1954,7 @@ soap_getutf8(struct soap *soap) if (c < 0xFC) return ((soap_wchar)(c & 0x03) << 24) | (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; return ((soap_wchar)(c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | (soap_wchar)(soap_get1(soap) & 0x3F); +#endif } #endif @@ -1965,7 +2064,7 @@ soap_gethex(struct soap *soap, int *n) } } #else - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; for (;;) { int i; @@ -2132,7 +2231,7 @@ soap_getbase64(struct soap *soap, int *n, int malloc_flag) m = (m << 6) + b; j++; } - else if (!soap_blank(c + '+')) + else if (!soap_coblank(c + '+')) { soap->error = SOAP_TYPE; return NULL; } @@ -2149,7 +2248,7 @@ soap_getbase64(struct soap *soap, int *n, int malloc_flag) } } #else - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; for (;;) { int i; @@ -2205,7 +2304,7 @@ soap_getbase64(struct soap *soap, int *n, int malloc_flag) m = (m << 6) + b; j++; } - else if (!soap_blank(c + '+')) + else if (!soap_coblank(c + '+')) { soap->error = SOAP_TYPE; return NULL; } @@ -2237,11 +2336,15 @@ soap_xop_forward(struct soap *soap, unsigned char **ptr, int *size, char **id, c /* TODO: this code to be obsoleted with new import/xop.h conventions */ short body = soap->body; /* should save type too? */ if (!soap_peek_element(soap)) - { if (!soap_element_begin_in(soap, "xop:Include", 0, NULL)) + { if (!soap_element_begin_in(soap, ":Include", 0, NULL)) { if (soap_attachment_forward(soap, ptr, size, id, type, options) - || (soap->body && soap_element_end_in(soap, "xop:Include"))) + || (soap->body && soap_element_end_in(soap, ":Include"))) return soap->error; } + else if (soap->error == SOAP_TAG_MISMATCH) + soap_retry(soap); + else + return soap->error; } soap->body = body; return SOAP_OK; @@ -2307,10 +2410,12 @@ SOAP_FMAC2 soap_strdup(struct soap *soap, const char *s) { char *t = NULL; if (s) - { size_t l = strlen(s) + 1; - t = (char*)soap_malloc(soap, l); + { size_t n = strlen(s); + t = (char*)soap_malloc(soap, n + 1); if (t) - soap_memcpy((void*)t, l, (const void*)s, l); + { soap_memcpy((void*)t, n, (const void*)s, n); + t[n] = '\0'; + } } return t; } @@ -2325,13 +2430,15 @@ SOAP_FMAC2 soap_wstrdup(struct soap *soap, const wchar_t *s) { wchar_t *t = NULL; if (s) - { size_t n = 0; + { size_t n = 0, m; while (s[n]) n++; - n = sizeof(wchar_t)*(n+1); - t = (wchar_t*)soap_malloc(soap, n); + m = sizeof(wchar_t) * n; + t = (wchar_t*)soap_malloc(soap, m + sizeof(wchar_t)); if (t) - soap_memcpy((void*)t, n, (const void*)s, n); + { soap_memcpy((void*)t, m, (const void*)s, m); + t[n] = L'\0'; + } } return t; } @@ -2389,9 +2496,9 @@ soap_wstrtrim(struct soap *soap, wchar_t *s) SOAP_FMAC1 struct soap_blist* SOAP_FMAC2 -soap_new_block(struct soap *soap) +soap_alloc_block(struct soap *soap) { struct soap_blist *p; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New block sequence (prev=%p)\n", soap->blist)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New block sequence (prev=%p)\n", (void*)soap->blist)); p = (struct soap_blist*)SOAP_MALLOC(soap, sizeof(struct soap_blist)); if (!p) { soap->error = SOAP_EOM; @@ -2425,7 +2532,7 @@ soap_push_block(struct soap *soap, struct soap_blist *b, size_t n) b->head = p; p->size = n; b->size += n; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push block %p of %u bytes on %lu previous blocks (%lu bytes total)\n", p, (unsigned int)n, (unsigned long)b->item, (unsigned long)b->size)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push block %p of %u bytes on %lu previous blocks (%lu bytes total)\n", (void*)p, (unsigned int)n, (unsigned long)b->item, (unsigned long)b->size)); b->item++; return (void*)(p + 1); /* skip block header and point to n allocated bytes */ } @@ -2462,7 +2569,7 @@ soap_pop_block(struct soap *soap, struct soap_blist *b) b->size -= p->size; b->head = p->next; b->item--; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Pop block %p (%lu items of %lu bytes total)\n", p, (unsigned long)b->item, (unsigned long)b->size)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Pop block %p (%lu items of %lu bytes total)\n", (void*)p, (unsigned long)b->item, (unsigned long)b->size)); SOAP_FREE(soap, p); } #endif @@ -2481,7 +2588,7 @@ soap_update_pointers(struct soap *soap, const char *dst, const char *src, size_t #ifndef WITH_NOIDREF if ((soap->version && !(soap->imode & SOAP_XML_TREE)) || (soap->mode & SOAP_XML_GRAPH)) { int i; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update pointers %p (%lu bytes) -> %p\n", src, (unsigned long)len, dst)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update pointers %p (%lu bytes) -> %p\n", (void*)src, (unsigned long)len, (void*)dst)); for (i = 0; i < SOAP_IDHASH; i++) { struct soap_ilist *ip; for (ip = soap->iht[i]; ip; ip = ip->next) @@ -2490,31 +2597,31 @@ soap_update_pointers(struct soap *soap, const char *dst, const char *src, size_t if (ip->shaky) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update shaky id='%s'\n", ip->id)); if (ip->ptr && ip->ptr >= start && ip->ptr < end) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update ptr %p -> %p\n", ip->ptr, (const char*)ip->ptr + (dst-src))); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update ptr %p -> %p\n", ip->ptr, (void*)((const char*)ip->ptr + (dst-src)))); ip->ptr = (void*)((const char*)ip->ptr + (dst-src)); } for (q = &ip->link; q; q = (void**)p) { p = *q; if (p && p >= start && p < end) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Link update id='%s' %p -> %p\n", ip->id, p, (const char*)p + (dst-src))); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Link update id='%s' %p -> %p\n", ip->id, p, (void*)((const char*)p + (dst-src)))); *q = (void*)((const char*)p + (dst-src)); } } for (q = &ip->copy; q; q = (void**)p) { p = *q; if (p && p >= start && p < end) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy chain update id='%s' %p -> %p\n", ip->id, p, (const char*)p + (dst-src))); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy chain update id='%s' %p -> %p\n", ip->id, p, (void*)((const char*)p + (dst-src)))); *q = (void*)((const char*)p + (dst-src)); } } for (fp = ip->flist; fp; fp = fp->next) { if (fp->ptr >= start && fp->ptr < end) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy list update id='%s' target type=%d %p -> %p\n", ip->id, fp->type, fp->ptr, (char*)fp->ptr + (dst-src))); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy list update id='%s' target type=%d %p -> %p\n", ip->id, fp->type, fp->ptr, (void*)((char*)fp->ptr + (dst-src)))); fp->ptr = (void*)((const char*)fp->ptr + (dst-src)); } } if (ip->smart && ip->smart >= start && ip->smart < end) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Smart shared pointer update %p -> %p\n", ip->smart, (const char*)ip->smart + (dst-src))); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Smart shared pointer update %p -> %p\n", ip->smart, (void*)((const char*)ip->smart + (dst-src)))); ip->smart = (void*)((const char*)ip->smart + (dst-src)); } } @@ -2527,7 +2634,7 @@ soap_update_pointers(struct soap *soap, const char *dst, const char *src, size_t #ifndef WITH_LEANER for (xp = soap->xlist; xp; xp = xp->next) { if (xp->ptr && (void*)xp->ptr >= start && (void*)xp->ptr < end) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update attachment id='%s' %p -> %p\n", xp->id ? xp->id : SOAP_STR_EOS, xp->ptr, (char*)xp->ptr + (dst-src))); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update attachment id='%s' %p -> %p\n", xp->id ? xp->id : SOAP_STR_EOS, (void*)xp->ptr, (void*)((char*)xp->ptr + (dst-src)))); xp->ptr = (unsigned char**)((char*)xp->ptr + (dst-src)); xp->size = (int*)((char*)xp->size + (dst-src)); xp->type = (char**)((char*)xp->type + (dst-src)); @@ -2589,7 +2696,7 @@ soap_resolve(struct soap *soap) while (q) { void *p = *q; *q = ip->ptr; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... link %p -> %p\n", q, ip->ptr)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... link %p -> %p\n", (void*)q, ip->ptr)); q = (void**)p; } while ((fp = *fpp)) @@ -2639,7 +2746,7 @@ soap_resolve(struct soap *soap) DBGLOG(TEST, if (q) SOAP_MESSAGE(fdebug, "Traversing copy chain to resolve id='%s'\n", ip->id)); ip->copy = NULL; do - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... copy %p -> %p (%u bytes)\n", ip->ptr, q, (unsigned int)ip->size)); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... copy %p -> %p (%u bytes)\n", ip->ptr, (void*)q, (unsigned int)ip->size)); p = *q; soap_memcpy((void*)q, ip->size, (const void*)ip->ptr, ip->size); q = (void**)p; @@ -2660,7 +2767,7 @@ soap_resolve(struct soap *soap) flag = 1; } } - else + else if (*ip->id == '#') id = ip->id; } } @@ -2714,7 +2821,7 @@ soap_first_block(struct soap *soap, struct soap_blist *b) p = q; } while (p); b->head = r; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "First block %p\n", r + 1)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "First block %p\n", (void*)(r + 1))); return (char*)(r + 1); } #endif @@ -2732,7 +2839,7 @@ soap_next_block(struct soap *soap, struct soap_blist *b) p = b->head; if (p) { b->head = p->next; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Next block %p, deleting current block\n", b->head ? b->head + 1 : NULL)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Next block %p, deleting current block\n", (void*)(b->head ? b->head + 1 : NULL))); SOAP_FREE(soap, p); if (b->head) return (char*)(b->head + 1); @@ -2810,12 +2917,12 @@ soap_save_block(struct soap *soap, struct soap_blist *b, char *p, int flag) if (b->size) { if (!p) p = (char*)soap_malloc(soap, b->size); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Save all %lu blocks in contiguous memory space of %u bytes (%p->%p)\n", (unsigned long)b->item, (unsigned int)b->size, b->head, p)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Save all %lu blocks in contiguous memory space of %u bytes (%p->%p)\n", (unsigned long)b->item, (unsigned int)b->size, (void*)b->head, (void*)p)); if (p) { s = p; for (q = soap_first_block(soap, b); q; q = soap_next_block(soap, b)) { n = soap_block_size(soap, b); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy %u bytes from %p to %p\n", (unsigned int)n, q, s)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy %u bytes from %p to %p\n", (unsigned int)n, (void*)q, (void*)s)); if (flag) soap_update_pointers(soap, s, q, n); soap_memcpy((void*)s, n, (const void*)q, n); @@ -2857,7 +2964,7 @@ soap_putsizesoffsets(struct soap *soap, const char *type, const int *size, const (SOAP_SNPRINTF(soap->type + l, sizeof(soap->type) - l - 1, 20), t, size[i]); } } - soap_strncat(soap->type, sizeof(soap->type), "]", 1); + (void)soap_strncat(soap->type, sizeof(soap->type), "]", 1); return soap->type; } #endif @@ -2877,7 +2984,7 @@ soap_putoffsets(struct soap *soap, const int *offset, int dim) { size_t l = strlen(soap->arrayOffset); (SOAP_SNPRINTF(soap->arrayOffset + l, sizeof(soap->arrayOffset) - l - 1, 20), ",%d", offset[i]); } - soap_strncat(soap->arrayOffset, sizeof(soap->arrayOffset), "]", 1); + (void)soap_strncat(soap->arrayOffset, sizeof(soap->arrayOffset), "]", 1); } return soap->arrayOffset; } @@ -3111,8 +3218,16 @@ soap_current_namespace_tag(struct soap *soap, const char *tag) if (np) { if (np->index >= 0) return soap->namespaces[np->index].ns; - if (np->ns && *np->ns) - return soap_strdup(soap, np->ns); + if (np->ns) + { s = np->ns; + if (*s) + return soap_strdup(soap, s); + do + np = np->next; + while (np && *np->id); /* find if there is any other default namespace */ + if (np) + return soap_strdup(soap, s); + } } return NULL; } @@ -3303,14 +3418,16 @@ SOAP_FMAC1 int SOAP_FMAC2 soap_match_array(struct soap *soap, const char *type) -{ if (*soap->arrayType) - if (soap_match_tag(soap, soap->arrayType, type) - && soap_match_tag(soap, soap->arrayType, "xsd:anyType") - && soap_match_tag(soap, soap->arrayType, "xsd:ur-type") - ) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array type mismatch: '%s' '%s'\n", soap->arrayType, type)); - return SOAP_TAG_MISMATCH; +{ if (type && *soap->arrayType) + { if (soap->version == 1 || !strchr(type, '[')) + { if (soap_match_tag(soap, soap->arrayType, type) + && soap_match_tag(soap, soap->arrayType, "xsd:anyType") + && soap_match_tag(soap, soap->arrayType, "xsd:ur-type")) + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SOAP array type mismatch: '%s' '%s'\n", soap->arrayType, type)); + return SOAP_TAG_MISMATCH; + } } + } return SOAP_OK; } #endif @@ -3351,7 +3468,7 @@ soap_ssl_server_context(struct soap *soap, unsigned short flags, const char *key { int err; soap->keyfile = keyfile; #if defined(VXWORKS) && defined(WM_SECURE_KEY_STORAGE) - soap->keyid = keyid; + soap->keyid = keyid; /* vxWorks compatible */ #endif soap->password = password; soap->cafile = cafile; @@ -3433,7 +3550,7 @@ soap_ssl_client_context(struct soap *soap, unsigned short flags, const char *key #endif { soap->keyfile = keyfile; #if defined(VXWORKS) && defined(WM_SECURE_KEY_STORAGE) - soap->keyid = keyid; + soap->keyid = keyid; /* vxWorks compatible */ #endif soap->password = password; soap->cafile = cafile; @@ -3478,19 +3595,18 @@ soap_ssl_crl(struct soap *soap, const char *crlfile) #ifdef WITH_OPENSSL if (crlfile && soap->ctx) { -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) +#if (OPENSSL_VERSION_NUMBER > 0x00907000L) X509_STORE *store = SSL_CTX_get_cert_store(soap->ctx); if (*crlfile) { int ret; X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if (!lookup) + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't create X509_LOOKUP object", SOAP_SSL_ERROR); ret = X509_load_crl_file(lookup, crlfile, X509_FILETYPE_PEM); if (ret <= 0) - return soap_set_receiver_error(soap, soap_ssl_error(soap, ret), "Can't read CRL file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, soap_ssl_error(soap, ret), "Can't read CRL PEM file", SOAP_SSL_ERROR); } - X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); - X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); - X509_STORE_set1_param(store, param); - X509_VERIFY_PARAM_free(param); + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #endif } else @@ -3500,7 +3616,7 @@ soap_ssl_crl(struct soap *soap, const char *crlfile) if (crlfile && soap->xcred) { if (*crlfile) if (gnutls_certificate_set_x509_crl_file(soap->xcred, crlfile, GNUTLS_X509_FMT_PEM) < 0) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CRL file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CRL PEM file", SOAP_SSL_ERROR); } else soap->crlfile = crlfile; /* activate later when xcred is available */ @@ -3528,12 +3644,24 @@ soap_ssl_init() SSL_load_error_strings(); #endif if (!RAND_load_file("/dev/urandom", 1024)) - { char buf[1024]; + { /* /dev/urandom should exist, if not we do some pertubations to seed the OpenSSL PRNG */ + char buf[1024]; RAND_seed(buf, sizeof(buf)); - while (!RAND_status()) - { int r = rand(); +#ifdef HAVE_RANDOM + srandom((unsigned long)time(NULL)); +#else + srand((unsigned int)time(NULL)); +#endif + do + { +#ifdef HAVE_RANDOM + long r = random(); /* we actually do no use random() anywhere, except to help seed the OpenSSL PRNG */ + RAND_seed(&r, sizeof(long)); +#else + int r = rand(); /* we actually do no use rand() anywhere, except to help seed the OpenSSL PRNG */ RAND_seed(&r, sizeof(int)); - } +#endif + } while (!RAND_status()); } #endif #ifdef WITH_GNUTLS @@ -3587,6 +3715,13 @@ soap_ssl_error(struct soap *soap, int ret) while ((r = ERR_get_error())) { size_t l = strlen(soap->msgbuf); ERR_error_string_n(r, soap->msgbuf + l, sizeof(soap->msgbuf) - l); + l = strlen(soap->msgbuf); + if (l + 1 < sizeof(soap->msgbuf)) + soap->msgbuf[l++] = '\n'; + if (ERR_GET_REASON(r) == SSL_R_CERTIFICATE_VERIFY_FAILED && l < sizeof(soap->msgbuf)) + { const char *s = X509_verify_cert_error_string(SSL_get_verify_result(soap->ssl)); + (SOAP_SNPRINTF(soap->msgbuf + l, sizeof(soap->msgbuf) - l, strlen(s)), "%s", s); + } } } else @@ -3617,8 +3752,7 @@ soap_ssl_error(struct soap *soap, int ret) #ifdef WITH_SYSTEMSSL static int ssl_recv(int sk, void *s, int n, char *user) -{ - (void)user; +{ (void)user; return recv(sk, s, n, 0); } #endif @@ -3628,8 +3762,7 @@ ssl_recv(int sk, void *s, int n, char *user) #ifdef WITH_SYSTEMSSL static int ssl_send(int sk, void *s, int n, char *user) -{ - (void)user; +{ (void)user; return send(sk, s, n, 0); } #endif @@ -3645,7 +3778,7 @@ ssl_auth_init(struct soap *soap) long flags; int mode; #if defined(VXWORKS) && defined(WM_SECURE_KEY_STORAGE) - EVP_PKEY* pkey; + EVP_PKEY* pkey; /* vxWorks compatible */ #endif if (!soap_ssl_init_done) soap_ssl_init(); @@ -3672,13 +3805,13 @@ ssl_auth_init(struct soap *soap) } if (soap->cafile || soap->capath) { if (!SSL_CTX_load_verify_locations(soap->ctx, soap->cafile, soap->capath)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA PEM file", SOAP_SSL_ERROR); if (soap->cafile && (soap->ssl_flags & SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION)) SSL_CTX_set_client_CA_list(soap->ctx, SSL_load_client_CA_file(soap->cafile)); } if (!(soap->ssl_flags & SOAP_SSL_NO_DEFAULT_CA_PATH)) { if (!SSL_CTX_set_default_verify_paths(soap->ctx)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read default CA file and/or directory", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read default CA PEM file and/or directory", SOAP_SSL_ERROR); } if (soap->crlfile) { if (soap_ssl_crl(soap, soap->crlfile)) @@ -3688,14 +3821,14 @@ ssl_auth_init(struct soap *soap) #if 1 if (soap->keyfile) { if (!SSL_CTX_use_certificate_chain_file(soap->ctx, soap->keyfile)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't find or read certificate in key file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't find or read certificate in private key PEM file", SOAP_SSL_ERROR); if (soap->password) { SSL_CTX_set_default_passwd_cb_userdata(soap->ctx, (void*)soap->password); SSL_CTX_set_default_passwd_cb(soap->ctx, ssl_password); } #ifndef WM_SECURE_KEY_STORAGE if (!SSL_CTX_use_PrivateKey_file(soap->ctx, soap->keyfile, SSL_FILETYPE_PEM)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read private key PEM file", SOAP_SSL_ERROR); #endif } #else @@ -3707,20 +3840,21 @@ ssl_auth_init(struct soap *soap) if (!soap->cafile) { if (soap->keyfile) { if (!SSL_CTX_use_certificate_chain_file(soap->ctx, soap->keyfile)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't find or read certificate in key file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't find or read certificate in private key PEM file", SOAP_SSL_ERROR); if (!SSL_CTX_use_PrivateKey_file(soap->ctx, soap->keyfile, SSL_FILETYPE_PEM)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read private key PEM file", SOAP_SSL_ERROR); } } else /* use cafile for (server) cert and keyfile for (server) key */ { if (!SSL_CTX_use_certificate_chain_file(soap->ctx, soap->cafile)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA PEM file", SOAP_SSL_ERROR); if (soap->keyfile) if (!SSL_CTX_use_PrivateKey_file(soap->ctx, soap->keyfile, SSL_FILETYPE_PEM)) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read private key PEM file", SOAP_SSL_ERROR); } #endif #if defined(VXWORKS) && defined(WM_SECURE_KEY_STORAGE) + /* vxWorks compatible */ pkey = ipcom_key_db_pkey_get(soap->keyid); if (!pkey) return soap_set_receiver_error(soap, "SSL error", "Can't find key", SOAP_SSL_ERROR); @@ -3728,13 +3862,18 @@ ssl_auth_init(struct soap *soap) return soap_set_receiver_error(soap, "SSL error", "Can't read key", SOAP_SSL_ERROR); #endif if ((soap->ssl_flags & SOAP_SSL_RSA)) - { RSA *rsa = RSA_generate_key(SOAP_SSL_RSA_BITS, RSA_F4, NULL, NULL); - if (!SSL_CTX_set_tmp_rsa(soap->ctx, rsa)) - { if (rsa) - RSA_free(rsa); - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't set RSA key", SOAP_SSL_ERROR); + { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + if (SSL_CTX_need_tmp_RSA(soap->ctx)) +#endif + { RSA *rsa = RSA_generate_key(SOAP_SSL_RSA_BITS, RSA_F4, NULL, NULL); + if (!rsa || !SSL_CTX_set_tmp_rsa(soap->ctx, rsa)) + { if (rsa) + RSA_free(rsa); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't set RSA key", SOAP_SSL_ERROR); + } + RSA_free(rsa); } - RSA_free(rsa); } else if (soap->dhfile) { DH *dh = 0; @@ -3743,7 +3882,7 @@ ssl_auth_init(struct soap *soap) /* if dhfile is numeric, treat it as a key length to generate DH params which can take a while */ if (n >= 512 && s && *s == '\0') #if defined(VXWORKS) - DH_generate_parameters_ex(dh, n, 2/*or 5*/, NULL); + DH_generate_parameters_ex(dh, n, 2/*or 5*/, NULL); /* vxWorks compatible */ #else dh = DH_generate_parameters(n, 2/*or 5*/, NULL, NULL); #endif @@ -3751,7 +3890,7 @@ ssl_auth_init(struct soap *soap) { BIO *bio; bio = BIO_new_file(soap->dhfile, "r"); if (!bio) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read DH file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read DH PEM file", SOAP_SSL_ERROR); dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); } @@ -3810,7 +3949,7 @@ ssl_auth_init(struct soap *soap) { gnutls_certificate_allocate_credentials(&soap->xcred); if (soap->cafile) { if (gnutls_certificate_set_x509_trust_file(soap->xcred, soap->cafile, GNUTLS_X509_FMT_PEM) < 0) - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA PEM file", SOAP_SSL_ERROR); } if (soap->crlfile) { if (soap_ssl_crl(soap, soap->crlfile)) @@ -3818,7 +3957,7 @@ ssl_auth_init(struct soap *soap) } if (soap->keyfile) { if (gnutls_certificate_set_x509_key_file(soap->xcred, soap->keyfile, soap->keyfile, GNUTLS_X509_FMT_PEM) < 0) /* Assumes that key and cert(s) are concatenated in the keyfile */ - return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR); + return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read private key PEM file", SOAP_SSL_ERROR); } } if ((soap->ssl_flags & SOAP_SSL_CLIENT)) @@ -3955,9 +4094,9 @@ ssl_verify_callback(int ok, X509_STORE_CTX *store) int err = X509_STORE_CTX_get_error(store); X509 *cert = X509_STORE_CTX_get_current_cert(store); fprintf(stderr, "\nDEBUG mode TLS/SSL warnings:\nSSL verify error %d or warning with certificate at depth %d: %s\n", err, X509_STORE_CTX_get_error_depth(store), X509_verify_cert_error_string(err)); - X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); + X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)-1); fprintf(stderr, " certificate issuer: %s\n", buf); - X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)-1); fprintf(stderr, " certificate subject: %s\n", buf); /* accept self-signed certificates and certificates out of date */ switch (err) @@ -4289,7 +4428,7 @@ tcp_gethost(struct soap *soap, const char *addr, struct in_addr *inaddr) { soap_int32 iadd = -1; struct hostent hostent, *host = &hostent; #ifdef VXWORKS - int hostint; + int hostint; /* vxWorks compatible */ /* inet_addr(), and hostGetByName() expect "char *"; addr is a "const char *". */ iadd = inet_addr((char*)addr); #else @@ -4319,6 +4458,7 @@ tcp_gethost(struct soap *soap, const char *addr, struct in_addr *inaddr) #elif defined(HAVE_GETHOSTBYNAME_R) host = gethostbyname_r(addr, &hostent, soap->buf, sizeof(soap->buf), &soap->errnum); #elif defined(VXWORKS) + /* vxWorks compatible */ /* If the DNS resolver library resolvLib has been configured in the vxWorks * image, a query for the host IP address is sent to the DNS server, if the * name was not found in the local host table. */ @@ -4341,7 +4481,7 @@ tcp_gethost(struct soap *soap, const char *addr, struct in_addr *inaddr) return SOAP_ERR; } #ifdef VXWORKS - inaddr->s_addr = hostint; + inaddr->s_addr = hostint; /* vxWorks compatible */ #else if (soap_memcpy((void*)inaddr, sizeof(struct in_addr), (const void*)host->h_addr, (size_t)host->h_length)) return soap->error = SOAP_EOM; @@ -4371,8 +4511,67 @@ tcp_connect(struct soap *soap, const char *endpoint, const char *host, int port) int retries; #endif if (soap_valid_socket(soap->socket)) + { if ((soap->omode & SOAP_IO_UDP) && soap->socket == soap->master) + { +#ifdef IP_MULTICAST_TTL +#ifndef WITH_IPV6 + if (soap->fresolve(soap, host, &soap->peer.in.sin_addr)) + { soap_set_receiver_error(soap, tcp_error(soap), "get host by name failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, soap->socket); + return soap->socket = SOAP_INVALID_SOCKET; + } + soap->peer.in.sin_port = htons((short)port); +#else + if (getaddrinfo(host, soap_int2s(soap, port), &hints, &res) || !res) + { soap_set_receiver_error(soap, SOAP_GAI_STRERROR(err), "getaddrinfo failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, soap->socket); + return soap->socket = SOAP_INVALID_SOCKET; + } + if (soap_memcpy((void*)&soap->peer.storage, sizeof(soap->peer.storage), (const void*)res->ai_addr, res->ai_addrlen)) + { soap->error = SOAP_EOM; + soap->fclosesocket(soap, soap->socket); + freeaddrinfo(res); + return soap->socket = SOAP_INVALID_SOCKET; + } + soap->peerlen = res->ai_addrlen; + freeaddrinfo(res); +#endif + if (soap->ipv4_multicast_ttl) + { unsigned char ttl = soap->ipv4_multicast_ttl; + if (setsockopt(soap->socket, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl))) + { soap->errnum = soap_socket_errno(soap->socket); + soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_TTL failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, soap->socket); + return soap->socket = SOAP_INVALID_SOCKET; + } + } + if (soap->ipv4_multicast_if && !soap->ipv6_multicast_if) + { if (setsockopt(soap->socket, IPPROTO_IP, IP_MULTICAST_IF, (char*)soap->ipv4_multicast_if, sizeof(struct in_addr))) +#ifndef WINDOWS + { soap->errnum = soap_socket_errno(soap->socket); + soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_IF failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, soap->socket); + return soap->socket = SOAP_INVALID_SOCKET; + } +#else +#ifndef IP_MULTICAST_IF +#define IP_MULTICAST_IF 2 +#endif + if (setsockopt(soap->socket, IPPROTO_IP, IP_MULTICAST_IF, (char*)soap->ipv4_multicast_if, sizeof(struct in_addr))) + { soap->errnum = soap_socket_errno(soap->socket); + soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_IF failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, soap->socket); + return soap->socket = SOAP_INVALID_SOCKET; + } +#endif + } +#endif + soap->errmode = 0; + return soap->socket; + } soap->fclosesocket(soap, soap->socket); - soap->socket = SOAP_INVALID_SOCKET; + soap->socket = SOAP_INVALID_SOCKET; + } if (tcp_init(soap)) { soap->errnum = 0; soap_set_receiver_error(soap, tcp_error(soap), "TCP init failed in tcp_connect()", SOAP_TCP_ERROR); @@ -4544,6 +4743,7 @@ again: in6addr->sin6_scope_id = soap->ipv6_multicast_if; } #endif +#endif #ifdef IP_MULTICAST_TTL if ((soap->omode & SOAP_IO_UDP)) { if (soap->ipv4_multicast_ttl) @@ -4553,7 +4753,7 @@ again: soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_TTL failed in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); #ifdef WITH_IPV6 - freeaddrinfo(ressave); + freeaddrinfo(ressave); #endif return SOAP_INVALID_SOCKET; } @@ -4565,7 +4765,7 @@ again: soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_IF failed in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); #ifdef WITH_IPV6 - freeaddrinfo(ressave); + freeaddrinfo(ressave); #endif return SOAP_INVALID_SOCKET; } @@ -4578,7 +4778,7 @@ again: soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_IF failed in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); #ifdef WITH_IPV6 - freeaddrinfo(ressave); + freeaddrinfo(ressave); #endif return SOAP_INVALID_SOCKET; } @@ -4587,12 +4787,36 @@ again: } #endif #endif -#endif - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Opening socket=%d to host='%s' port=%d\n", sk, host, port)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Opening socket=%d to host='%s' port=%d\n", (int)sk, host, port)); #ifndef WITH_IPV6 soap->peerlen = sizeof(soap->peer.in); memset((void*)&soap->peer.in, 0, sizeof(soap->peer.in)); soap->peer.in.sin_family = AF_INET; + if (soap->client_port >= 0) + { struct sockaddr_in addr; + memset((void*)&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(soap->client_port); + if (bind(sk, (struct sockaddr*)&addr, sizeof(addr))) + { soap->errnum = soap_socket_errno(sk); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind before connect\n")); + soap_set_receiver_error(soap, tcp_error(soap), "bind failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, sk); + return SOAP_INVALID_SOCKET; + } + soap->client_port = -1; /* disable bind before connect, so need to set it again before the next connect */ + } +#ifndef WIN32 + if (soap->client_interface) + { if (inet_pton(AF_INET, soap->client_interface, &soap->peer.in.sin_addr) != 1) + { soap->errnum = soap_socket_errno(sk); + soap_set_receiver_error(soap, tcp_error(soap), "inet_pton() failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, sk); + return SOAP_INVALID_SOCKET; + } + soap->client_interface = NULL; /* disable client interface, so need to set it again before the next connect */ + } +#endif soap->errmode = 2; if (soap->proxy_host) { if (soap->fresolve(soap, soap->proxy_host, &soap->peer.in.sin_addr)) @@ -4616,6 +4840,31 @@ again: return sk; #endif #else + if (soap->client_port >= 0) + { struct sockaddr_in6 addr; + memset((void*)&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(soap->client_port); + if (bind(sk, (struct sockaddr*)&addr, sizeof(addr))) + { soap->errnum = soap_socket_errno(sk); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind before connect\n")); + soap_set_receiver_error(soap, tcp_error(soap), "bind failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, sk); + freeaddrinfo(ressave); + return SOAP_INVALID_SOCKET; + } + soap->client_port = -1; /* disable bind before connect, so need to set t again before the next connect */ + } + if (soap->client_interface) + { if (inet_pton(AF_INET6, soap->client_interface, res->ai_addr) != 1) + { soap->errnum = soap_socket_errno(sk); + soap_set_receiver_error(soap, tcp_error(soap), "inet_pton() failed in tcp_connect()", SOAP_TCP_ERROR); + soap->fclosesocket(soap, sk); + freeaddrinfo(ressave); + return SOAP_INVALID_SOCKET; + } + soap->client_interface = NULL; /* disable client interface, so need to set it again before the next connect */ + } if ((soap->omode & SOAP_IO_UDP)) { if (soap_memcpy((void*)&soap->peer.storage, sizeof(soap->peer.storage), (const void*)res->ai_addr, res->ai_addrlen)) { soap->error = SOAP_EOM; @@ -4656,8 +4905,7 @@ again: goto again; } else if (soap->connect_timeout && (err == SOAP_EINPROGRESS || err == SOAP_EAGAIN || err == SOAP_EWOULDBLOCK)) - { - SOAP_SOCKLEN_T k; + { SOAP_SOCKLEN_T k; for (;;) { int r; r = tcp_select(soap, sk, SOAP_TCP_SELECT_SND, soap->connect_timeout); @@ -4753,27 +5001,30 @@ again: size_t n = soap->count; /* save the content length */ const char *userid, *passwd; int status = soap->status; /* save the current status/command */ - short keep_alive = soap->keep_alive; /* save the KA status */ + int keep_alive = soap->keep_alive; /* save the KA status */ soap->omode &= ~SOAP_ENC; /* mask IO and ENC */ soap->omode |= SOAP_IO_BUFFER; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connecting to %s proxy server %s for destination endpoint %s\n", soap->proxy_http_version, soap->proxy_host, endpoint)); #ifdef WITH_NTLM if (soap->ntlm_challenge) { if (soap_ntlm_handshake(soap, SOAP_CONNECT, endpoint, host, port)) - return soap->error; + { soap->fclosesocket(soap, sk); + return soap->socket = SOAP_INVALID_SOCKET; + } } #endif if (soap_begin_send(soap)) { soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } soap->status = SOAP_CONNECT; - soap->keep_alive = 1; + if (!soap->keep_alive) + soap->keep_alive = -1; /* must keep alive */ soap->error = soap->fpost(soap, endpoint, host, port, NULL, NULL, 0); if (soap->error || soap_end_send_flush(soap)) { soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } soap->keep_alive = keep_alive; soap->omode = om; @@ -4784,7 +5035,7 @@ again: soap->error = soap->fparse(soap); if (soap->error) { soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } soap->status = status; /* restore */ soap->userid = userid; /* restore */ @@ -4793,7 +5044,7 @@ again: soap->count = n; /* restore */ if (soap_begin_send(soap)) { soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } if (endpoint) soap_strcpy(soap->endpoint, sizeof(soap->endpoint), endpoint); /* restore */ @@ -4805,14 +5056,14 @@ again: { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL required, but no ctx set\n")); soap->fclosesocket(soap, sk); soap->error = SOAP_SSL_ERROR; - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } if (!soap->ssl) { soap->ssl = SSL_new(soap->ctx); if (!soap->ssl) { soap->fclosesocket(soap, sk); soap->error = SOAP_SSL_ERROR; - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } else @@ -4827,13 +5078,13 @@ again: if (!(soap->ssl_flags & SOAP_SSLv3) && !SSL_set_tlsext_host_name(soap->ssl, host)) { soap_set_receiver_error(soap, "SSL/TLS error", "SNI failed", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } #elif (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && defined(SSL_CTRL_SET_TLSEXT_HOSTNAME) if (!SSL_ctrl(soap->ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (void*)host)) { soap_set_receiver_error(soap, "SSL/TLS error", "SNI failed", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } #endif bio = BIO_new_socket((int)sk, BIO_NOCLOSE); @@ -4862,19 +5113,19 @@ again: { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL_connect/select error in tcp_connect\n")); soap_set_receiver_error(soap, soap_ssl_error(soap, r), "SSL_connect failed in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } if (s == 0 && retries-- <= 0) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL/TLS connect timeout\n")); soap_set_receiver_error(soap, "Timeout", "SSL_connect failed in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } else { soap_set_receiver_error(soap, soap_ssl_error(soap, r), "SSL_connect error in tcp_connect()", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } } while (!SSL_is_init_finished(soap->ssl)); @@ -4886,7 +5137,7 @@ again: if ((err = SSL_get_verify_result(soap->ssl)) != X509_V_OK) { soap_set_sender_error(soap, X509_verify_cert_error_string(err), "SSL/TLS certificate presented by peer cannot be verified in tcp_connect()", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } if (!(soap->ssl_flags & SOAP_SSL_SKIP_HOST_CHECK)) { X509_NAME *subj; @@ -4901,7 +5152,7 @@ again: if (!peer) { soap_set_sender_error(soap, "SSL/TLS error", "No SSL/TLS certificate was presented by the peer in tcp_connect()", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } #if (OPENSSL_VERSION_NUMBER < 0x0090800fL) ext_count = X509_get_ext_count(peer); @@ -4988,7 +5239,7 @@ again: break; name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, i)); if (name) - { if (!soap_tag_cmp(host, (const char*)M_ASN1_STRING_data(name))) + { if (!soap_tag_cmp(host, (const char*)ASN1_STRING_data(name))) ok = 1; else { unsigned char *tmp = NULL; @@ -5011,7 +5262,7 @@ again: if (!ok) { soap_set_sender_error(soap, "SSL/TLS error", "SSL/TLS certificate host name mismatch in tcp_connect()", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } } @@ -5020,7 +5271,7 @@ again: soap->ssl_flags |= SOAP_SSL_CLIENT; if (!soap->session && (soap->error = soap->fsslauth(soap)) != SOAP_OK) { soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } gnutls_transport_set_ptr(soap->session, (gnutls_transport_ptr_t)(long)sk); /* Set SSL sockets to non-blocking */ @@ -5053,14 +5304,14 @@ again: if (r) { soap_set_sender_error(soap, soap_ssl_error(soap, r), "SSL/TLS handshake failed", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } if ((soap->ssl_flags & SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION)) { const char *err = ssl_verify(soap, host); if (err) { soap->fclosesocket(soap, sk); soap->error = soap_set_sender_error(soap, "SSL/TLS verify error", err, SOAP_SSL_ERROR); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } #endif @@ -5070,7 +5321,7 @@ again: { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL required, but no ctx set\n")); soap->fclosesocket(soap, sk); soap->error = SOAP_SSL_ERROR; - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } /* Connect timeout: set SSL sockets to non-blocking */ retries = 0; @@ -5097,7 +5348,7 @@ again: err = gsk_attribute_set_callback(soap->ssl, GSK_IO_CALLBACK, &local_io); if (err != GSK_OK) { soap_set_receiver_error(soap, gsk_strerror(err), "SYSTEM SSL error in tcp_connect()", SOAP_SSL_ERROR); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } /* Try connecting until success or timeout (when nonblocking) */ while ((err = gsk_secure_socket_init(soap->ssl)) != GSK_OK) @@ -5110,19 +5361,19 @@ again: { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL_connect/select error in tcp_connect\n")); soap_set_receiver_error(soap, gsk_strerror(err), "gsk_secure_socket_init failed in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } if (r == 0 && retries-- <= 0) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL/TLS connect timeout\n")); soap_set_receiver_error(soap, "Timeout", "in tcp_connect()", SOAP_TCP_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } else { soap_set_receiver_error(soap, gsk_strerror(err), "gsk_secure_socket_init() failed in tcp_connect()", SOAP_SSL_ERROR); soap->fclosesocket(soap, sk); - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; } } #endif @@ -5131,7 +5382,7 @@ again: #else soap->fclosesocket(soap, sk); soap->error = SOAP_SSL_ERROR; - return SOAP_INVALID_SOCKET; + return soap->socket = SOAP_INVALID_SOCKET; #endif } if (soap->recv_timeout || soap->send_timeout) @@ -5155,6 +5406,10 @@ tcp_select(struct soap *soap, SOAP_SOCKET sk, int flags, int timeout) int retries = 0; int eintr = SOAP_MAXEINTR; soap->errnum = 0; + if (!soap_valid_socket(sk)) + { soap->error = SOAP_EOF; + return -1; + } #ifndef WIN32 #if !defined(FD_SETSIZE) || defined(__QNX__) || defined(QNX) /* no FD_SETSIZE or select() is not MT safe on some QNX: always poll */ @@ -5286,7 +5541,7 @@ tcp_disconnect(struct soap *soap) { #ifdef WITH_OPENSSL if (soap->ssl) - { int r, s = 0; + { int r; if (soap->session) { SSL_SESSION_free(soap->session); soap->session = NULL; @@ -5325,7 +5580,11 @@ tcp_disconnect(struct soap *soap) DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connection lost...\n")); soap->fclosesocket(soap, soap->socket); soap->socket = SOAP_INVALID_SOCKET; +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + ERR_clear_error(); +#else ERR_remove_state(0); +#endif SSL_free(soap->ssl); soap->ssl = NULL; return SOAP_OK; @@ -5337,20 +5596,19 @@ tcp_disconnect(struct soap *soap) } } if (r != 1) - { s = ERR_get_error(); - if (s) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Shutdown failed: %d\n", SSL_get_error(soap->ssl, r))); - if (soap_valid_socket(soap->socket) && !(soap->omode & SOAP_IO_UDP)) - { soap->fclosesocket(soap, soap->socket); - soap->socket = SOAP_INVALID_SOCKET; - } + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Shutdown failed: %d\n", SSL_get_error(soap->ssl, r))); + if (soap_valid_socket(soap->socket) && !(soap->omode & SOAP_IO_UDP)) + { soap->fclosesocket(soap, soap->socket); + soap->socket = SOAP_INVALID_SOCKET; } } SSL_free(soap->ssl); soap->ssl = NULL; - if (s) - return SOAP_SSL_ERROR; +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + ERR_clear_error(); +#else ERR_remove_state(0); +#endif } #endif #ifdef WITH_GNUTLS @@ -5613,8 +5871,7 @@ soap_poll(struct soap *soap) { #ifdef WITH_OPENSSL if (soap->imode & SOAP_ENC_SSL) - { - if (soap_valid_socket(soap->socket) + { if (soap_valid_socket(soap->socket) && (r & SOAP_TCP_SELECT_SND) && (!(r & SOAP_TCP_SELECT_RCV) || SSL_peek(soap->ssl, soap->tmpbuf, 1) > 0)) @@ -5636,7 +5893,7 @@ soap_poll(struct soap *soap) return soap->error = SOAP_TCP_ERROR; } } - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Polling: other end down on socket=%d select=%d\n", soap->socket, r)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Polling: other end down on socket=%d select=%d\n", (int)soap->socket, r)); return SOAP_EOF; #else (void)soap; @@ -5674,13 +5931,13 @@ soap_accept(struct soap *soap) return soap->socket = soap->master; #endif for (;;) - { if (soap->accept_timeout || soap->send_timeout || soap->recv_timeout) + { if (soap->accept_timeout) { for (;;) { int r; - r = tcp_select(soap, soap->master, SOAP_TCP_SELECT_ALL, soap->accept_timeout ? soap->accept_timeout : 60); + r = tcp_select(soap, soap->master, SOAP_TCP_SELECT_ALL, soap->accept_timeout); if (r > 0) break; - if (!r && soap->accept_timeout) + if (!r) { soap_set_receiver_error(soap, "Timeout", "accept failed in soap_accept()", SOAP_TCP_ERROR); return SOAP_INVALID_SOCKET; } @@ -5694,10 +5951,6 @@ soap_accept(struct soap *soap) } } } - if (soap->accept_timeout) - SOAP_SOCKNONBLOCK(soap->master) - else - SOAP_SOCKBLOCK(soap->master) n = (int)sizeof(soap->peer); soap->socket = soap->faccept(soap, soap->master, &soap->peer.addr, &n); soap->peerlen = (size_t)n; @@ -5720,7 +5973,7 @@ soap_accept(struct soap *soap) (SOAP_SNPRINTF(soap->host, sizeof(soap->host), 80), "%u.%u.%u.%u", (int)(soap->ip>>24)&0xFF, (int)(soap->ip>>16)&0xFF, (int)(soap->ip>>8)&0xFF, (int)soap->ip&0xFF); soap->port = (int)ntohs(soap->peer.in.sin_port); /* does not return port number on some systems */ #endif - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Accept socket=%d at port=%d from IP='%s'\n", soap->socket, soap->port, soap->host)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Accept socket=%d at port=%d from IP='%s'\n", (int)soap->socket, soap->port, soap->host)); #ifndef WITH_LEAN if ((soap->accept_flags & SO_LINGER)) { struct linger linger; @@ -5769,7 +6022,7 @@ soap_accept(struct soap *soap) #endif #endif #endif - soap->keep_alive = (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0); + soap->keep_alive = -(((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0); if (soap->send_timeout || soap->recv_timeout) SOAP_SOCKNONBLOCK(soap->socket) else @@ -5798,7 +6051,7 @@ SOAP_FMAC2 soap_closesock(struct soap *soap) { int status = soap->error; #ifndef WITH_LEANER - if (status) /* close on error: attachment state is not to be trusted */ + if (status && status < 200) /* attachment state is not to be trusted */ { soap->mime.first = NULL; soap->mime.last = NULL; soap->dime.first = NULL; @@ -5827,7 +6080,6 @@ soap_closesock(struct soap *soap) /******************************************************************************/ -#ifndef WITH_NOIO #ifndef PALM_1 SOAP_FMAC1 int @@ -5839,7 +6091,6 @@ soap_force_closesock(struct soap *soap) return SOAP_OK; } #endif -#endif /******************************************************************************/ @@ -5974,8 +6225,12 @@ soap_done(struct soap *soap) soap->ctx = NULL; } } +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + ERR_clear_error(); +#else ERR_remove_state(0); #endif +#endif #ifdef WITH_GNUTLS if (soap->state == SOAP_INIT) { if (soap->xcred) @@ -6012,15 +6267,7 @@ soap_done(struct soap *soap) gsk_environment_close(&soap->ctx); #endif #ifdef WITH_C_LOCALE - if (soap->c_locale) - { -# ifdef WIN32 - _free_locale(soap->c_locale); -# else - freelocale(soap->c_locale); -# endif - soap->c_locale = NULL; - } + SOAP_FREELOCALE(soap); #endif #ifdef WITH_ZLIB if (soap->d_stream) @@ -6075,6 +6322,9 @@ http_parse(struct soap *soap) soap->ntlm_challenge = NULL; #endif soap->proxy_from = NULL; + soap->cors_origin = NULL; + soap->cors_method = NULL; + soap->cors_header = NULL; do { soap->length = 0; soap->http_content = NULL; @@ -6089,7 +6339,7 @@ http_parse(struct soap *soap) s = strchr(soap->msgbuf, ' '); if (s) { soap->status = (unsigned short)soap_strtoul(s, &s, 10); - if (!soap_blank((soap_wchar)*s)) + if (!soap_coblank((soap_wchar)*s)) soap->status = 0; } else @@ -6111,8 +6361,9 @@ http_parse(struct soap *soap) if (s) { char *t; *s = '\0'; - do s++; - while (*s && *s <= 32); + do + { s++; + } while (*s && *s <= 32); if (*s == '"') s++; t = s + strlen(s) - 1; @@ -6134,13 +6385,10 @@ http_parse(struct soap *soap) DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Finished HTTP header parsing, status = %d\n", soap->status)); s = strstr(soap->msgbuf, "HTTP/"); if (s && s[7] != '1') - { if (soap->keep_alive == 1) - soap->keep_alive = 0; + { soap->keep_alive = 0; if (soap->status == 0 && (soap->omode & SOAP_IO) == SOAP_IO_CHUNK) /* soap->status == 0 for HTTP request */ soap->omode = (soap->omode & ~SOAP_IO) | SOAP_IO_STORE; /* HTTP 1.0 does not support chunked transfers */ } - if (soap->keep_alive < 0) - soap->keep_alive = 1; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Keep alive connection = %d\n", soap->keep_alive)); if (soap->status == 0) { size_t l = 0; @@ -6160,7 +6408,8 @@ http_parse(struct soap *soap) } if (s && httpcmd) { size_t m, n, k; - while (soap_blank(soap->msgbuf[l])) + int err = 0; + while (soap->msgbuf[l] && soap_coblank((soap_wchar)soap->msgbuf[l])) l++; m = strlen(soap->endpoint); n = m + (s - soap->msgbuf) - l - 1; @@ -6171,13 +6420,16 @@ http_parse(struct soap *soap) k = n - m + 1; if (k >= sizeof(soap->path)) k = sizeof(soap->path) - 1; - while (k > 0 && soap_blank(soap->msgbuf[l + k - 1])) + while (k > 0 && soap_coblank((soap_wchar)soap->msgbuf[l + k - 1])) k--; - soap_strncpy(soap->path, sizeof(soap->path), soap->msgbuf + l, k); + if (soap_strncpy(soap->path, sizeof(soap->path), soap->msgbuf + l, k)) + return soap->error = 414; if (*soap->path && *soap->path != '/') - soap_strncpy(soap->endpoint, sizeof(soap->endpoint), soap->path, k); + err = soap_strncpy(soap->endpoint, sizeof(soap->endpoint), soap->path, k); else - soap_strncat(soap->endpoint, sizeof(soap->endpoint), soap->path, k); + err = soap_strncat(soap->endpoint, sizeof(soap->endpoint), soap->path, k); + if (err) + return soap->error = 414; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Target endpoint='%s' path='%s'\n", soap->endpoint, soap->path)); if (httpcmd > 1) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "HTTP %s handler\n", soap->msgbuf)); @@ -6242,25 +6494,26 @@ http_parse_header(struct soap *soap, const char *key, const char *val) else #endif soap_strcpy(soap->endpoint, sizeof(soap->endpoint), "http://"); - soap_strncat(soap->endpoint, sizeof(soap->endpoint), val, sizeof(soap->endpoint) - 9); + if (soap_strncat(soap->endpoint, sizeof(soap->endpoint), val, sizeof(soap->endpoint) - 9)) + return soap->error = SOAP_HDR; } #ifndef WITH_LEANER else if (!soap_tag_cmp(key, "Content-Type")) { const char *action; soap->http_content = soap_strdup(soap, val); - if (soap_get_header_attribute(soap, val, "application/dime")) + if (soap_http_header_attribute(soap, val, "application/dime")) soap->imode |= SOAP_ENC_DIME; - else if (soap_get_header_attribute(soap, val, "multipart/related") - || soap_get_header_attribute(soap, val, "multipart/form-data")) - { soap->mime.boundary = soap_strdup(soap, soap_get_header_attribute(soap, val, "boundary")); - soap->mime.start = soap_strdup(soap, soap_get_header_attribute(soap, val, "start")); + else if (soap_http_header_attribute(soap, val, "multipart/related") + || soap_http_header_attribute(soap, val, "multipart/form-data")) + { soap->mime.boundary = soap_strdup(soap, soap_http_header_attribute(soap, val, "boundary")); + soap->mime.start = soap_strdup(soap, soap_http_header_attribute(soap, val, "start")); soap->imode |= SOAP_ENC_MIME; } - action = soap_get_header_attribute(soap, val, "action"); + action = soap_http_header_attribute(soap, val, "action"); if (action) { if (*action == '"') { soap->action = soap_strdup(soap, action + 1); - if (*soap->action) + if (soap->action && *soap->action) soap->action[strlen(soap->action) - 1] = '\0'; } else @@ -6291,11 +6544,11 @@ http_parse_header(struct soap *soap, const char *key, const char *val) else if (!soap_tag_cmp(key, "Accept-Encoding")) { #ifdef WITH_GZIP - if (strchr(val, '*') || soap_get_header_attribute(soap, val, "gzip")) + if (strchr(val, '*') || soap_http_header_attribute(soap, val, "gzip")) soap->zlib_out = SOAP_ZLIB_GZIP; else #endif - if (strchr(val, '*') || soap_get_header_attribute(soap, val, "deflate")) + if (strchr(val, '*') || soap_http_header_attribute(soap, val, "deflate")) soap->zlib_out = SOAP_ZLIB_DEFLATE; else soap->zlib_out = SOAP_ZLIB_NONE; @@ -6307,9 +6560,8 @@ http_parse_header(struct soap *soap, const char *key, const char *val) soap->imode |= SOAP_IO_CHUNK; } else if (!soap_tag_cmp(key, "Connection")) - { if (!soap_tag_cmp(val, "keep-alive")) - soap->keep_alive = -soap->keep_alive; - else if (!soap_tag_cmp(val, "close")) + { + if (!soap_tag_cmp(val, "close")) soap->keep_alive = 0; } #if !defined(WITH_LEAN) || defined(WITH_NTLM) @@ -6340,7 +6592,7 @@ http_parse_header(struct soap *soap, const char *key, const char *val) soap->ntlm_challenge = soap_strdup(soap, val + 4); else #endif - soap->authrealm = soap_strdup(soap, soap_get_header_attribute(soap, val + 6, "realm")); + soap->authrealm = soap_strdup(soap, soap_http_header_attribute(soap, val + 6, "realm")); } else if (!soap_tag_cmp(key, "Expect")) { if (!soap_tag_cmp(val, "100-continue")) @@ -6365,6 +6617,16 @@ http_parse_header(struct soap *soap, const char *key, const char *val) else if (!soap_tag_cmp(key, "X-Forwarded-For")) { soap->proxy_from = soap_strdup(soap, val); } + else if (!soap_tag_cmp(key, "Origin")) + { soap->origin = soap_strdup(soap, val); + soap->cors_origin = soap->cors_allow; + } + else if (!soap_tag_cmp(key, "Access-Control-Request-Method")) + { soap->cors_method = soap_strdup(soap, val); + } + else if (!soap_tag_cmp(key, "Access-Control-Request-Headers")) + { soap->cors_header = soap_strdup(soap, val); + } #ifdef WITH_COOKIES else if (!soap_tag_cmp(key, "Cookie") || !soap_tag_cmp(key, "Cookie2") @@ -6385,7 +6647,7 @@ http_parse_header(struct soap *soap, const char *key, const char *val) SOAP_FMAC1 const char* SOAP_FMAC2 -soap_get_header_attribute(struct soap *soap, const char *line, const char *key) +soap_http_header_attribute(struct soap *soap, const char *line, const char *key) { const char *s = line; if (s) { while (*s) @@ -6451,7 +6713,7 @@ soap_decode(char *buf, size_t len, const char *val, const char *sep) *t++ = *s++; } else - { while (*s && !soap_blank((soap_wchar)*s) && !strchr(sep, *s) && --i) + { while (*s && !soap_coblank((soap_wchar)*s) && !strchr(sep, *s) && --i) { if (*s == '%' && s[1] && s[2]) { *t++ = ((s[1] >= 'A' ? (s[1] & 0x7) + 9 : s[1] - '0') << 4) + (s[2] >= 'A' ? (s[2] & 0x7) + 9 : s[2] - '0'); @@ -6461,7 +6723,7 @@ soap_decode(char *buf, size_t len, const char *val, const char *sep) *t++ = *s++; } } - buf[len - 1] = '\0'; /* appease */ + buf[len - 1] = '\0'; /* appease static checkers that get confused */ } *t = '\0'; while (*s && !strchr(sep, *s)) @@ -6521,7 +6783,12 @@ http_405(struct soap *soap) #ifndef PALM_1 static int http_200(struct soap *soap) -{ return soap_send_empty_response(soap, 200); +{ if (soap->origin && soap->cors_method) /* CORS Origin and Access-Control-Request-Method headers */ + { soap->cors_origin = soap->cors_allow; /* modify this code or hook your own soap->fopt() callback with logic */ + soap->cors_methods = "GET, POST, HEAD, OPTIONS"; + soap->cors_headers = soap->cors_header; + } + return soap_send_empty_response(soap, 200); } #endif #endif @@ -6548,6 +6815,12 @@ http_post(struct soap *soap, const char *endpoint, const char *host, int port, c case SOAP_CONNECT: s = "CONNECT"; break; + case SOAP_HEAD: + s = "HEAD"; + break; + case SOAP_OPTIONS: + s = "OPTIONS"; + break; default: s = "POST"; } @@ -6599,12 +6872,35 @@ http_post(struct soap *soap, const char *endpoint, const char *host, int port, c err = soap->fposthdr(soap, "User-Agent", "gSOAP/2.8"); if (err) return err; + if (soap->origin) + { err = soap->fposthdr(soap, "Origin", soap->origin); + if (err) + return err; + if (soap->status == SOAP_OPTIONS) + { + err = soap->fposthdr(soap, "Access-Control-Request-Method", soap->cors_method ? soap->cors_method : "POST"); + if (err) + return err; + if (soap->cors_header) + { err = soap->fposthdr(soap, "Access-Control-Request-Headers", soap->cors_header); + if (err) + return err; + } + } + } err = soap_puthttphdr(soap, SOAP_OK, count); if (err) return err; +#ifndef WITH_LEANER + if (soap->imode & SOAP_ENC_MTOM) + { err = soap->fposthdr(soap, "Accept", "multipart/related,application/xop+xml,*/*;q=0.8"); + if (err) + return err; + } +#endif #ifdef WITH_ZLIB #ifdef WITH_GZIP - err = soap->fposthdr(soap, "Accept-Encoding", "gzip, deflate"); + err = soap->fposthdr(soap, "Accept-Encoding", "gzip,deflate"); #else err = soap->fposthdr(soap, "Accept-Encoding", "deflate"); #endif @@ -6724,9 +7020,9 @@ http_response(struct soap *soap, int status, size_t count) httpOutputEnable(soap->rpmreqid); #endif #ifdef WMW_RPM_IO - if (soap->rpmreqid || soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) /* RPM behaves as if standalone */ + if (soap->rpmreqid || soap_valid_socket(soap->master) || soap_valid_socket(soap->socket) || soap->os) /* RPM behaves as if standalone */ #else - if (soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) /* standalone application (socket) or CGI (stdin/out)? */ + if (soap_valid_socket(soap->master) || soap_valid_socket(soap->socket) || soap->os) /* standalone application (socket) or CGI (stdin/out)? */ #endif (SOAP_SNPRINTF(http, sizeof(http), strlen(soap->http_version) + 5), "HTTP/%s", soap->http_version); else @@ -6768,6 +7064,32 @@ http_response(struct soap *soap, int status, size_t count) err = soap->fposthdr(soap, "Server", "gSOAP/2.8"); if (err) return err; + if (soap->cors_origin) + { err = soap->fposthdr(soap, "Access-Control-Allow-Origin", soap->cors_origin); + if (err) + return err; + err = soap->fposthdr(soap, "Access-Control-Allow-Credentials", "true"); + if (err) + return err; + if (soap->cors_methods) + { err = soap->fposthdr(soap, "Access-Control-Allow-Methods", soap->cors_methods); + if (err) + return err; + if (soap->cors_headers) + { err = soap->fposthdr(soap, "Access-Control-Allow-Headers", soap->cors_headers); + if (err) + return err; + } + } + } + if (soap->x_frame_options) + { err = soap->fposthdr(soap, "X-Frame-Options", soap->x_frame_options); + if (err) + return err; + } + soap->cors_origin = NULL; + soap->cors_methods = NULL; + soap->cors_headers = NULL; err = soap_puthttphdr(soap, status, count); if (err) return err; @@ -6788,7 +7110,7 @@ int SOAP_FMAC2 soap_response(struct soap *soap, int status) { size_t count; - if (!(soap->omode & (SOAP_ENC_XML | SOAP_IO_STORE /* this tests for chunking too */)) + if (!(soap->omode & (SOAP_ENC_PLAIN | SOAP_IO_STORE /* this tests for chunking too */)) && (status == SOAP_HTML || status == SOAP_FILE)) soap->omode = (soap->omode & ~SOAP_IO) | SOAP_IO_STORE; soap->status = status; @@ -6796,7 +7118,7 @@ soap_response(struct soap *soap, int status) if (soap_begin_send(soap)) return soap->error; #ifndef WITH_NOHTTP - if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_XML)) + if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_PLAIN)) { int n = soap->mode; soap->mode &= ~(SOAP_IO | SOAP_ENC_ZLIB); if ((n & SOAP_IO) != SOAP_IO_FLUSH) @@ -6832,19 +7154,19 @@ soap_extend_url(struct soap *soap, const char *s, const char *t) { char *r = strchr(soap->msgbuf, '?'); if (r) { if (*t == '?') - { soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "&", 1); - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), t + 1, strlen(t) - 1); + { (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "&", 1); + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), t + 1, strlen(t) - 1); } else /* *t == '/' */ { size_t l = r - soap->msgbuf; *r = '\0'; - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), t, strlen(t)); + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), t, strlen(t)); if (s) - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), s + l, strlen(s + l)); + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), s + l, strlen(s + l)); } } else - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), t, strlen(t)); + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), t, strlen(t)); } return soap->msgbuf; } @@ -6859,9 +7181,9 @@ SOAP_FMAC2 soap_extend_url_query(struct soap *soap, const char *s, const char *t) { soap_extend_url(soap, s, t); if (strchr(soap->msgbuf, '?')) - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "&", 1); + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "&", 1); else - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "?", 1); + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "?", 1); return soap->msgbuf; } #endif @@ -6870,6 +7192,38 @@ soap_extend_url_query(struct soap *soap, const char *s, const char *t) #ifndef PALM_1 SOAP_FMAC1 +void +SOAP_FMAC2 +soap_url_query(struct soap *soap, const char *s, const char *t) +{ size_t n = strlen(s); + if (n) + { char *r = soap->msgbuf; + size_t k = n - (s[n-1] == '='); + while ((r = strchr(r, '{')) != NULL) + if (!strncmp(++r, s, k) && r[k] == '}') + break; + if (r) + { size_t m = t ? strlen(t) : 0; + soap_memmove(r + m - 1, soap->msgbuf + sizeof(soap->msgbuf) - (r + n + 1), r + k + 1, strlen(r + k + 1) + 1); + if (m) + soap_memmove(r - 1, soap->msgbuf + sizeof(soap->msgbuf) - (r - 1), t, m); + } + else + { (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), s, n); + if (t) + { size_t m = strlen(soap->msgbuf); + soap_encode_url(t, soap->msgbuf + m, sizeof(soap->msgbuf) - m); + } + (void)soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), "&", 1); + } + } +} +#endif + +/******************************************************************************/ + +#ifndef PALM_1 +SOAP_FMAC1 size_t SOAP_FMAC2 soap_encode_url(const char *s, char *t, size_t len) @@ -7059,7 +7413,8 @@ soap_clr_cookie(struct soap *soap, const char *name, const char *domain, const c path++; for (p = &soap->cookies, q = *p; q; q = *p) { if (!strcmp(q->name, name) && (!q->domain || !strcmp(q->domain, domain)) && (!q->path || !strncmp(q->path, path, strlen(q->path)))) - { if (q->value) + { SOAP_FREE(soap, q->name); + if (q->value) SOAP_FREE(soap, q->value); if (q->domain) SOAP_FREE(soap, q->domain); @@ -7117,12 +7472,12 @@ soap_cookie_expire(struct soap *soap, const char *name, const char *domain, cons SOAP_FMAC1 int SOAP_FMAC2 -soap_set_cookie_expire(struct soap *soap, const char *name, long expire, const char *domain, const char *path) +soap_set_cookie_expire(struct soap *soap, const char *name, long maxage, const char *domain, const char *path) { struct soap_cookie *p; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set cookie expiration max-age=%ld: cookie='%s' domain='%s' path='%s'\n", expire, name, domain ? domain : "(null)", path ? path : "(null)")); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set cookie expiration max-age=%ld: cookie='%s' domain='%s' path='%s'\n", maxage, name, domain ? domain : "(null)", path ? path : "(null)")); p = soap_cookie(soap, name, domain, path); if (p) - { p->maxage = expire; + { p->maxage = maxage; p->modified = 1; return SOAP_OK; } @@ -7218,13 +7573,37 @@ soap_putsetcookies(struct soap *soap) { (SOAP_SNPRINTF(s, 4096 - (s-tmp), 29), ";Max-Age=%ld", p->maxage); s += strlen(s); } +#if !defined(WITH_LEAN) +#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME) + if (p->maxage >= 0 && s-tmp < 4056) + { time_t n = time(NULL) + p->maxage; + struct tm T, *pT = &T; + size_t l = 0; + /* format is Wed, 09 Jun 2021 10:18:14 GMT */ +#if defined(HAVE_GMTIME_R) + if (gmtime_r(&n, pT) != SOAP_FUNC_R_ERR) + l = strftime(s, 4096 - (s-tmp), ";Expires=%a, %d %b %Y %H:%M:%S GMT", pT); +#else + pT = gmtime(&n); + if (pT) + l = strftime(s, 4096 - (s-tmp), ";Expires=%a, %d %b %Y %H:%M:%S GMT", pT); +#endif + s += l; + } +#endif +#endif if (s-tmp < 4073 && (p->secure #ifdef WITH_OPENSSL || soap->ssl #endif )) + { soap_strcpy(s, 4096 - (s-tmp), ";Secure"); + s += strlen(s); + } + if (s-tmp < 4071) + soap_strcpy(s, 4096 - (s-tmp), ";HttpOnly"); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set-Cookie: %s\n", tmp)); soap->error = soap->fposthdr(soap, "Set-Cookie", tmp); if (soap->error) @@ -7252,7 +7631,7 @@ soap_putcookies(struct soap *soap, const char *domain, const char *path, int sec if (*path == '/') path++; while ((q = *p)) - { if (q->expire && now > q->expire) + { if (q->expire && now >= q->expire) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Cookie %s expired\n", q->name)); SOAP_FREE(soap, q->name); if (q->value) @@ -7316,7 +7695,7 @@ soap_putcookies(struct soap *soap, const char *domain, const char *path, int sec s = tmp; } else if (s != tmp) - { *s++ = ' '; + { *s++ = ';'; } if (q->version != version && s-tmp < 4060) { (SOAP_SNPRINTF(s, 4096 - (s-tmp), 29), "$Version=%u;", q->version); @@ -7453,36 +7832,45 @@ soap_getcookies(struct soap *soap, const char *val) p->expire = now + soap_strtol(tmp, NULL, 10); } else if (p && !soap_tag_cmp(tmp, "Expires")) - { struct tm T; - char a[3]; - static const char mns[] = "anebarprayunulugepctovec"; - s = soap_decode_val(tmp, sizeof(tmp), s); - if (strlen(tmp) > 20) - { memset((void*)&T, 0, sizeof(T)); - a[0] = tmp[4]; - a[1] = tmp[5]; - a[2] = '\0'; - T.tm_mday = (int)soap_strtol(a, NULL, 10); - a[0] = tmp[8]; - a[1] = tmp[9]; - T.tm_mon = (int)(strstr(mns, a) - mns) / 2; - a[0] = tmp[11]; - a[1] = tmp[12]; - T.tm_year = 100 + (int)soap_strtol(a, NULL, 10); - a[0] = tmp[13]; - a[1] = tmp[14]; - T.tm_hour = (int)soap_strtol(a, NULL, 10); - a[0] = tmp[16]; - a[1] = tmp[17]; - T.tm_min = (int)soap_strtol(a, NULL, 10); - a[0] = tmp[19]; - a[1] = tmp[20]; - T.tm_sec = (int)soap_strtol(a, NULL, 10); - p->expire = soap_timegm(&T); + { if (*s == '=') + { s = soap_decode(tmp, sizeof(tmp), s + 1, ";"); + if (!p->expire && strlen(tmp) >= 23) + { char a[3]; + struct tm T; + static const char mns[] = "anebarprayunulugepctovec"; + const char *t = tmp + 4 + (tmp[3] == ','); + a[2] = '\0'; + memset((void*)&T, 0, sizeof(T)); + /* format is Wed, 09 Jun 2021 10:18:14 GMT (comma is optional?) */ + a[0] = t[0]; + a[1] = t[1]; + T.tm_mday = (int)soap_strtol(a, NULL, 10); + a[0] = t[4]; + a[1] = t[5]; + T.tm_mon = (int)(strstr(mns, a) - mns) / 2; + a[0] = t[9]; + a[1] = t[10]; + T.tm_year = 100 + (int)soap_strtol(a, NULL, 10); + a[0] = t[12]; + a[1] = t[13]; + T.tm_hour = (int)soap_strtol(a, NULL, 10); + a[0] = t[15]; + a[1] = t[16]; + T.tm_min = (int)soap_strtol(a, NULL, 10); + a[0] = t[18]; + a[1] = t[19]; + T.tm_sec = (int)soap_strtol(a, NULL, 10); + p->expire = soap_timegm(&T); + } } } else if (p && !soap_tag_cmp(tmp, "Secure")) - p->secure = 1; + { p->secure = 1; + s = soap_decode_val(tmp, sizeof(tmp), s); + } + else if (p && !soap_tag_cmp(tmp, "HttpOnly")) + { s = soap_decode_val(tmp, sizeof(tmp), s); + } else { if (p) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Got environment cookie='%s' value='%s' domain='%s' path='%s' expire=%ld secure=%d\n", p->name, p->value ? p->value : "(null)", p->domain ? p->domain : "(null)", p->path ? p->path : "(null)", p->expire, p->secure)); @@ -7517,9 +7905,11 @@ soap_getcookies(struct soap *soap, const char *val) soap_memcpy((void*)p->value, l, (const void*)tmp, l); } else - p->value = NULL; + { p->value = NULL; + } if (domain) - p->domain = domain; + { p->domain = domain; + } else if (*soap->host) { l = strlen(soap->host) + 1; p->domain = (char*)SOAP_MALLOC(soap, l); @@ -7527,9 +7917,11 @@ soap_getcookies(struct soap *soap, const char *val) soap_memcpy((void*)p->domain, l, (const void*)soap->host, l); } else - p->domain = NULL; + { p->domain = NULL; + } if (path) - p->path = path; + { p->path = path; + } else if (*soap->path) { l = strlen(soap->path) + 1; p->path = (char*)SOAP_MALLOC(soap, l); @@ -7601,6 +7993,7 @@ struct soap_cookie* SOAP_FMAC2 soap_copy_cookies(struct soap *copy, const struct soap *soap) { struct soap_cookie *p, **q, *r; + (void)copy; q = &r; for (p = soap->cookies; p; p = p->next) { *q = (struct soap_cookie*)SOAP_MALLOC(copy, sizeof(struct soap_cookie)); @@ -7765,7 +8158,7 @@ soap_embed(struct soap *soap, const void *p, const void *a, int n, int t) struct soap_plist *pp; if (soap->version == 2) soap->encoding = 1; - if (!p || (!soap->encodingStyle && !(soap->omode & SOAP_XML_GRAPH)) || (soap->omode & SOAP_XML_TREE)) + if (!p || (!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH)) || (soap->mode & SOAP_XML_TREE)) return 0; if (a) id = soap_array_pointer_lookup(soap, p, a, n, t, &pp); @@ -7883,11 +8276,12 @@ soap_begin_count(struct soap *soap) #endif { soap->mode = soap->omode; if ((soap->mode & SOAP_IO_UDP)) - { soap->mode |= SOAP_ENC_XML; - soap->mode &= ~SOAP_IO_CHUNK; + { soap->mode &= SOAP_IO; + soap->mode |= SOAP_IO_BUFFER; + soap->mode |= SOAP_ENC_PLAIN; } if ((soap->mode & SOAP_IO) == SOAP_IO_STORE - || (((soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_ENC_XML)) + || (((soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_ENC_PLAIN)) #ifndef WITH_LEANER && !soap->fpreparesend #endif @@ -7900,7 +8294,7 @@ soap_begin_count(struct soap *soap) if ((soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) == SOAP_IO_FLUSH) { if (!(soap->mode & SOAP_ENC_DIME)) soap->mode &= ~SOAP_IO_LENGTH; - if (soap->mode & SOAP_ENC_XML) + if (soap->mode & SOAP_ENC_PLAIN) soap->mode |= SOAP_IO_BUFFER; else soap->mode |= SOAP_IO_STORE; @@ -7935,7 +8329,7 @@ soap_begin_count(struct soap *soap) if (soap->fprepareinitsend && (soap->mode & SOAP_IO) != SOAP_IO_STORE && (soap->error = soap->fprepareinitsend(soap)) != SOAP_OK) return soap->error; #endif - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin count phase (socket=%d mode=0x%x count=%lu)\n", soap->socket, (unsigned int)soap->mode, (unsigned long)soap->count)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin count phase (socket=%d mode=0x%x count=%lu)\n", (int)soap->socket, (unsigned int)soap->mode, (unsigned long)soap->count)); return SOAP_OK; } #endif @@ -7967,21 +8361,22 @@ SOAP_FMAC1 int SOAP_FMAC2 soap_begin_send(struct soap *soap) -{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing for output to socket=%d/fd=%d\n", soap->socket, soap->sendfd)); +{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing for output to socket=%d/fd=%d\n", (int)soap->socket, soap->sendfd)); soap_free_ns(soap); soap->error = SOAP_OK; soap->mode = soap->omode | (soap->mode & (SOAP_IO_LENGTH | SOAP_ENC_DIME)); #ifndef WITH_LEAN if ((soap->mode & SOAP_IO_UDP)) - { soap->mode |= SOAP_ENC_XML; - soap->mode &= ~SOAP_IO_CHUNK; + { soap->mode &= SOAP_IO; + soap->mode |= SOAP_IO_BUFFER; + soap->mode |= SOAP_ENC_PLAIN; if (soap->count > sizeof(soap->buf)) return soap->error = SOAP_UDP_ERROR; } #endif #ifdef WITH_ZLIB if ((soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) == SOAP_IO_FLUSH) - { if (soap->mode & SOAP_ENC_XML) + { if (soap->mode & SOAP_ENC_PLAIN) soap->mode |= SOAP_IO_BUFFER; else soap->mode |= SOAP_IO_STORE; @@ -7989,7 +8384,7 @@ soap_begin_send(struct soap *soap) #endif if ((soap->mode & SOAP_IO) == SOAP_IO_FLUSH) { if (soap_valid_socket(soap->socket)) - { if (soap->count || (soap->mode & SOAP_IO_LENGTH) || (soap->mode & SOAP_ENC_XML)) + { if (soap->count || (soap->mode & SOAP_IO_LENGTH) || (soap->mode & SOAP_ENC_PLAIN)) soap->mode |= SOAP_IO_BUFFER; else soap->mode |= SOAP_IO_STORE; @@ -8003,7 +8398,7 @@ soap_begin_send(struct soap *soap) } soap->mode &= ~SOAP_IO_LENGTH; if ((soap->mode & SOAP_IO) == SOAP_IO_STORE) - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return soap->error; if (!(soap->mode & SOAP_IO_KEEPALIVE)) soap->keep_alive = 0; @@ -8039,6 +8434,9 @@ soap_begin_send(struct soap *soap) soap->position = 0; soap->mustUnderstand = 0; soap->encoding = 0; + soap->part = SOAP_BEGIN; + soap->event = 0; + soap->evlev = 0; soap->idnum = 0; soap->body = 1; soap->level = 0; @@ -8060,8 +8458,7 @@ soap_begin_send(struct soap *soap) soap->d_stream->avail_out = sizeof(soap->buf); #ifdef WITH_GZIP if (soap->zlib_out != SOAP_ZLIB_DEFLATE) - { if (soap_memcpy((void*)soap->z_buf, sizeof(soap->buf), (const void*)"\37\213\10\0\0\0\0\0\0\377", 10)) - return soap->error = SOAP_EOM; + { soap_memcpy((void*)soap->z_buf, sizeof(soap->buf), (const void*)"\37\213\10\0\0\0\0\0\0\377", 10); soap->d_stream->next_out = (Byte*)soap->z_buf + 10; soap->d_stream->avail_out = sizeof(soap->buf) - 10; soap->z_crc = crc32(0L, NULL, 0); @@ -8087,12 +8484,15 @@ soap_begin_send(struct soap *soap) if (soap->ssl) ERR_clear_error(); #endif - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin send phase (socket=%d mode=0x%x count=%lu)\n", soap->socket, soap->mode, (unsigned long)soap->count)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin send phase (socket=%d mode=0x%x count=%lu)\n", (int)soap->socket, soap->mode, (unsigned long)soap->count)); soap->part = SOAP_BEGIN; #ifndef WITH_LEANER if (soap->fprepareinitsend && (soap->mode & SOAP_IO) == SOAP_IO_STORE && (soap->error = soap->fprepareinitsend(soap)) != SOAP_OK) return soap->error; #endif +#ifndef WITH_LEAN + soap->start = time(NULL); +#endif return SOAP_OK; } #endif @@ -8124,7 +8524,7 @@ int SOAP_FMAC2 soap_reference(struct soap *soap, const void *p, int t) { struct soap_plist *pp; - if (!p || (!soap->encodingStyle && !(soap->omode & (SOAP_ENC_DIME|SOAP_ENC_MIME|SOAP_ENC_MTOM|SOAP_XML_GRAPH))) || (soap->omode & SOAP_XML_TREE)) + if (!p || (!soap->encodingStyle && !(soap->mode & (SOAP_ENC_DIME|SOAP_ENC_MIME|SOAP_ENC_MTOM|SOAP_XML_GRAPH))) || (soap->mode & SOAP_XML_TREE)) return 1; if (soap_pointer_lookup(soap, p, t, &pp)) { if (pp->mark1 == 0) @@ -8149,7 +8549,7 @@ int SOAP_FMAC2 soap_array_reference(struct soap *soap, const void *p, const void *a, int n, int t) { struct soap_plist *pp; - if (!p || !a || (!soap->encodingStyle && !(soap->omode & (SOAP_ENC_DIME|SOAP_ENC_MIME|SOAP_ENC_MTOM|SOAP_XML_GRAPH))) || (soap->omode & SOAP_XML_TREE)) + if (!p || !a || (!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH)) || (soap->mode & SOAP_XML_TREE)) return 1; if (soap_array_pointer_lookup(soap, p, a, n, t, &pp)) { if (pp->mark1 == 0) @@ -8159,7 +8559,34 @@ soap_array_reference(struct soap *soap, const void *p, const void *a, int n, int } else if (!soap_pointer_enter(soap, p, a, n, t, &pp)) return 1; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array reference %p ptr=%p n=%lu type=%d (%d %d)\n", p, a, (unsigned long)n, t, (int)pp->mark1, (int)pp->mark2)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array reference %p ptr=%p n=%lu t=%d (%d %d)\n", p, a, (unsigned long)n, t, (int)pp->mark1, (int)pp->mark2)); + return pp->mark1; +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_NOIDREF +#ifndef PALM_2 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_attachment_reference(struct soap *soap, const void *p, const void *a, int n, int t, const char *id, const char *type) +{ struct soap_plist *pp; + if (!p || !a || (!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH) && !id && !type) || (soap->mode & SOAP_XML_TREE)) + return 1; + if (soap_array_pointer_lookup(soap, p, a, n, t, &pp)) + { if (pp->mark1 == 0) + { pp->mark1 = 2; + pp->mark2 = 2; + } + } + else if (!soap_pointer_enter(soap, p, a, n, t, &pp)) + return 1; + if (id || type) + soap->mode |= SOAP_ENC_DIME; + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Attachment reference %p ptr=%p n=%lu t=%d (%d %d)\n", p, a, (unsigned long)n, t, (int)pp->mark1, (int)pp->mark2)); return pp->mark1; } #endif @@ -8174,7 +8601,7 @@ int SOAP_FMAC2 soap_embedded_id(struct soap *soap, int id, const void *p, int t) { struct soap_plist *pp = NULL; - if (id >= 0 || (!soap->encodingStyle && !(soap->omode & SOAP_XML_GRAPH)) || (soap->omode & SOAP_XML_TREE)) + if (id >= 0 || (!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH)) || (soap->mode & SOAP_XML_TREE)) return id; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded_id %p type=%d id=%d\n", p, t, id)); if (id < -1) @@ -8274,7 +8701,7 @@ SOAP_FMAC2 soap_attachment(struct soap *soap, const char *tag, int id, const void *p, const void *a, int n, const char *aid, const char *atype, const char *aoptions, const char *type, int t) { struct soap_plist *pp; int i; - if (!p || !a || (!aid && !atype)) + if (!p || !a || (!aid && !atype) || (!soap->encodingStyle && !(soap->mode & (SOAP_ENC_DIME|SOAP_ENC_MIME|SOAP_ENC_MTOM|SOAP_XML_GRAPH))) || (soap->mode & SOAP_XML_TREE)) return soap_element_id(soap, tag, id, p, a, n, type, t, NULL); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Attachment tag='%s' id='%s' (%d) type='%s'\n", tag, aid ? aid : SOAP_STR_EOS, id, atype ? atype : SOAP_STR_EOS)); i = soap_array_pointer_lookup(soap, p, a, n, t, &pp); @@ -8290,6 +8717,8 @@ soap_attachment(struct soap *soap, const char *tag, int id, const void *p, const if (!aid) { (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), strlen(soap->dime_id_format) + 20), soap->dime_id_format, id); aid = soap_strdup(soap, soap->tmpbuf); + if (!aid) + return -1; } /* Add MTOM xop:Include element when necessary */ /* TODO: this code to be obsoleted with new import/xop.h conventions */ @@ -8305,9 +8734,9 @@ soap_attachment(struct soap *soap, const char *tag, int id, const void *p, const { if (pp->mark1 != 3) { struct soap_multipart *content; if (soap->mode & SOAP_ENC_MTOM) - content = soap_new_multipart(soap, &soap->mime.first, &soap->mime.last, (char*)a, n); + content = soap_alloc_multipart(soap, &soap->mime.first, &soap->mime.last, (char*)a, n); else - content = soap_new_multipart(soap, &soap->dime.first, &soap->dime.last, (char*)a, n); + content = soap_alloc_multipart(soap, &soap->dime.first, &soap->dime.last, (char*)a, n); if (!content) { soap->error = SOAP_EOM; return -1; @@ -8318,7 +8747,7 @@ soap_attachment(struct soap *soap, const char *tag, int id, const void *p, const char *s = (char*)soap_malloc(soap, l); if (s) { s[0] = '<'; - soap_strncpy(s + 1, l - 1, aid + 4, l - 3); + (void)soap_strncpy(s + 1, l - 1, aid + 4, l - 3); s[l - 2] = '>'; s[l - 1] = '\0'; content->id = s; @@ -8443,7 +8872,7 @@ soap_malloc(struct soap *soap, size_t n) p = (char*)soap->fmalloc(soap, n); else { n += sizeof(short); - n += (-(long)n) & (sizeof(void*)-1); /* align at 4-, 8- or 16-byte boundary */ + n += (-(long)n) & (sizeof(void*)-1); /* align at 4-, 8- or 16-byte boundary by rounding up */ p = (char*)SOAP_MALLOC(soap, n + sizeof(void*) + sizeof(size_t)); if (!p) { soap->error = SOAP_EOM; @@ -8574,8 +9003,7 @@ soap_dealloc(struct soap *soap, void *p) if (p) { char **q; for (q = (char**)(void*)&soap->alist; *q; q = *(char***)q) - { - if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY) + { if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY) { #ifdef SOAP_MEM_DEBUG fprintf(stderr, "Data corruption in dynamic allocation (see logs)\n"); @@ -8666,7 +9094,7 @@ soap_delete(struct soap *soap, void *p) { while (*cp) { struct soap_clist *q = *cp; *cp = q->next; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Delete %p type=%d (cp=%p)\n", q->ptr, q->type, q)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Delete %p type=%d (cp=%p)\n", q->ptr, q->type, (void*)q)); if (q->fdelete(q)) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not dealloc data %p: deletion callback failed for object type %d\n", q->ptr, q->type)); #ifdef SOAP_MEM_DEBUG @@ -8696,8 +9124,7 @@ soap_delegate_deletion(struct soap *soap, struct soap *soap_to) size_t h; #endif for (q = (char**)(void*)&soap->alist; *q; q = *(char***)q) - { - if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY) + { if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY) { #ifdef SOAP_MEM_DEBUG fprintf(stderr, "Data corruption in dynamic allocation (see logs)\n"); @@ -8894,7 +9321,7 @@ soap_id_lookup(struct soap *soap, const char *id, void **p, int t, size_t n, uns { ip = soap_enter(soap, id, t, n); /* new hash table entry for string id */ if (!ip) return NULL; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding first href='%s' type=%d location=%p (%u bytes) level=%u\n", id, t, p, (unsigned int)n, k)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding first href='%s' type=%d location=%p (%u bytes) level=%u\n", id, t, (void*)p, (unsigned int)n, k)); *p = NULL; if (k) { int i; @@ -8923,7 +9350,7 @@ soap_id_lookup(struct soap *soap, const char *id, void **p, int t, size_t n, uns *p = ip->ptr; } else - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarded href='%s' type=%d location=%p (%u bytes) level=%u\n", id, t, p, (unsigned int)n, k)); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarded href='%s' type=%d location=%p (%u bytes) level=%u\n", id, t, (void*)p, (unsigned int)n, k)); if (fbase && fbase(t, ip->type) && !soap_type_punned(soap, ip)) { ip->type = t; ip->size = n; @@ -9083,7 +9510,7 @@ soap_id_enter(struct soap *soap, const char *id, void *p, int t, size_t n, const while (q) { void *r = *q; *q = p; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... link %p -> %p\n", q, p)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... link %p -> %p\n", (void*)q, p)); q = (void**)r; } ip->link = NULL; @@ -9263,13 +9690,15 @@ soap_end_send_flush(struct soap *soap) if (soap->os) { char *b = (char*)soap_push_block(soap, NULL, 1); if (b) + { *b = '\0'; *soap->os = soap_save_block(soap, NULL, NULL, 0); + } } else #endif { char *p; #ifndef WITH_NOHTTP - if (!(soap->mode & SOAP_ENC_XML)) + if (!(soap->mode & SOAP_ENC_PLAIN)) { soap->mode--; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Sending buffered message of length %u\n", (unsigned int)soap->blist->size)); if (soap->status >= SOAP_POST) @@ -9283,7 +9712,7 @@ soap_end_send_flush(struct soap *soap) #endif for (p = soap_first_block(soap, NULL); p; p = soap_next_block(soap, NULL)) { DBGMSG(SENT, p, soap_block_size(soap, NULL)); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Send %u bytes to socket=%d/fd=%d\n", (unsigned int)soap_block_size(soap, NULL), soap->socket, soap->sendfd)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Send %u bytes to socket=%d/fd=%d\n", (unsigned int)soap_block_size(soap, NULL), (int)soap->socket, soap->sendfd)); soap->error = soap->fsend(soap, p, soap_block_size(soap, NULL)); if (soap->error) { soap_end_block(soap, NULL); @@ -9300,7 +9729,7 @@ soap_end_send_flush(struct soap *soap) #ifndef WITH_LEANER else if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) { DBGMSG(SENT, "\r\n0\r\n\r\n", 7); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Send 7 bytes to socket=%d/fd=%d\n", soap->socket, soap->sendfd)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Send 7 bytes to socket=%d/fd=%d\n", (int)soap->socket, soap->sendfd)); soap->error = soap->fsend(soap, "\r\n0\r\n\r\n", 7); if (soap->error) return soap->error; @@ -9354,7 +9783,7 @@ soap_end_recv(struct soap *soap) { if (soap->mode & SOAP_MIME_POSTCHECK) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Post checking MIME attachments\n")); if (!soap->keep_alive) - soap->keep_alive = -1; + soap->keep_alive = -2; /* special case to keep alive */ #ifndef WITH_NOIDREF soap_resolve(soap); #endif @@ -9584,8 +10013,7 @@ SOAP_FMAC1 void SOAP_FMAC2 soap_set_recv_logfile(struct soap *soap, const char *logfile) -{ - (void)soap; (void)logfile; +{ (void)soap; (void)logfile; #ifdef SOAP_DEBUG soap_set_logfile(soap, SOAP_INDEX_RECV, logfile); #endif @@ -9597,8 +10025,7 @@ SOAP_FMAC1 void SOAP_FMAC2 soap_set_sent_logfile(struct soap *soap, const char *logfile) -{ - (void)soap; (void)logfile; +{ (void)soap; (void)logfile; #ifdef SOAP_DEBUG soap_set_logfile(soap, SOAP_INDEX_SENT, logfile); #endif @@ -9610,8 +10037,7 @@ SOAP_FMAC1 void SOAP_FMAC2 soap_set_test_logfile(struct soap *soap, const char *logfile) -{ - (void)soap; (void)logfile; +{ (void)soap; (void)logfile; #ifdef SOAP_DEBUG soap_set_logfile(soap, SOAP_INDEX_TEST, logfile); #endif @@ -9682,6 +10108,8 @@ soap_copy_context(struct soap *copy, const struct soap *soap) copy->bio = NULL; copy->ssl = NULL; copy->session = NULL; + copy->session_host[0] = '\0'; + copy->session_port = 443; #endif #ifdef WITH_GNUTLS copy->session = NULL; @@ -9744,10 +10172,10 @@ soap_copy_stream(struct soap *copy, struct soap *soap) copy->mode = soap->mode; copy->imode = soap->imode; copy->omode = soap->omode; - copy->master = soap->master; copy->socket = soap->socket; copy->sendsk = soap->sendsk; copy->recvsk = soap->recvsk; + copy->transfer_timeout = soap->transfer_timeout; copy->recv_timeout = soap->recv_timeout; copy->send_timeout = soap->send_timeout; copy->connect_timeout = soap->connect_timeout; @@ -9835,7 +10263,9 @@ soap_copy_stream(struct soap *copy, struct soap *soap) size_t n = sizeof(struct soap_nlist) + strlen(nq->id); np = (struct soap_nlist*)SOAP_MALLOC(copy, n); if (!np) + { np = nr; break; + } soap_memcpy((void*)np, n, (const void*)nq, n); np->next = nr; } @@ -9847,8 +10277,8 @@ soap_copy_stream(struct soap *copy, struct soap *soap) if (!s) s = soap->local_namespaces[np->index].ns; } - if (s && soap_push_namespace(copy, np->id, s) == NULL) - break; + if (s) + (void)soap_push_namespace(copy, np->id, s); nq = np; np = np->next; SOAP_FREE(copy, nq); @@ -9990,6 +10420,8 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->ipv6_multicast_if = 0; /* in_addr_t value */ soap->ipv4_multicast_if = NULL; /* points to struct in_addr or in_addr_t */ soap->ipv4_multicast_ttl = 0; /* 0: use default */ + soap->client_port = -1; /* client port to bind, -1 for none */ + soap->client_interface = NULL; /* client interface address, NULL for none */ #ifndef WITH_IPV6 soap->fresolve = tcp_gethost; #else @@ -10045,6 +10477,7 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->double_format = "%.17lG"; /* Alternative: use "%lG" */ soap->long_double_format = NULL; /* Defined in custom serializer custom/long_double.c */ soap->dime_id_format = "cid:id%d"; /* default DIME id format for int id index */ + soap->transfer_timeout = 0; soap->recv_timeout = 0; soap->send_timeout = 0; soap->connect_timeout = 0; @@ -10067,6 +10500,7 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->http_version = "1.1"; soap->proxy_http_version = "1.0"; soap->http_content = NULL; + soap->http_extra_header = NULL; soap->actor = NULL; soap->lang = "en"; soap->keep_alive = 0; @@ -10122,11 +10556,22 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->host[0] = '\0'; soap->path[0] = '\0'; soap->port = 0; + soap->override_host = NULL; + soap->override_port = 0; soap->action = NULL; soap->proxy_host = NULL; soap->proxy_port = 8080; soap->proxy_userid = NULL; soap->proxy_passwd = NULL; + soap->proxy_from = NULL; + soap->origin = NULL; + soap->cors_origin = NULL; + soap->cors_allow = "*"; + soap->cors_method = NULL; + soap->cors_header = NULL; + soap->cors_methods = NULL; + soap->cors_headers = NULL; + soap->x_frame_options = "SAMEORIGIN"; soap->prolog = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; #ifdef WITH_ZLIB soap->zlib_state = SOAP_ZLIB_NONE; @@ -10166,6 +10611,8 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->ssl = NULL; soap->ctx = NULL; soap->session = NULL; + soap->session_host[0] = '\0'; + soap->session_port = 443; soap->ssl_flags = SOAP_SSL_DEFAULT; soap->keyfile = NULL; soap->keyid = NULL; @@ -10219,6 +10666,8 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->dime.chunksize = 0; soap->dime.buflen = 0; #endif + soap->other = 0; + soap->root = -1; soap->null = 0; soap->position = 0; soap->encoding = 0; @@ -10236,7 +10685,10 @@ soap_versioning(soap_init)(struct soap *soap, soap_mode imode, soap_mode omode) soap->idnum = 0; soap->level = 0; soap->endpoint[0] = '\0'; + soap->status = 0; soap->error = SOAP_OK; + soap->errmode = 0; + soap->errnum = 0; } #endif @@ -10336,10 +10788,8 @@ soap_set_version(struct soap *soap, short version) /******************************************************************************/ #ifndef PALM_1 -SOAP_FMAC1 -void -SOAP_FMAC2 -soap_get_version(struct soap *soap) +static void +soap_version(struct soap *soap) { struct Namespace *p = soap->local_namespaces; if (p) { const char *ns = p[0].out; @@ -10351,7 +10801,7 @@ soap_get_version(struct soap *soap) SOAP_FREE(soap, p[1].out); p[1].out = (char*)SOAP_MALLOC(soap, sizeof(soap_enc1)); if (p[1].out) - soap_strncpy(p[1].out, sizeof(soap_enc1), soap_enc1, sizeof(soap_enc1) - 1); + (void)soap_strncpy(p[1].out, sizeof(soap_enc1), soap_enc1, sizeof(soap_enc1) - 1); } else if (!strcmp(ns, soap_env2)) { soap->version = 2; /* make sure we use SOAP 1.2 */ @@ -10359,7 +10809,7 @@ soap_get_version(struct soap *soap) SOAP_FREE(soap, p[1].out); p[1].out = (char*)SOAP_MALLOC(soap, sizeof(soap_enc2)); if (p[1].out) - soap_strncpy(p[1].out, sizeof(soap_enc2), soap_enc2, sizeof(soap_enc2) - 1); + (void)soap_strncpy(p[1].out, sizeof(soap_enc2), soap_enc2, sizeof(soap_enc2) - 1); } } } @@ -10401,8 +10851,8 @@ soap_set_namespaces(struct soap *soap, const struct Namespace *p) if (!s) s = ns[np->index].ns; } - if (s && soap_push_namespace(soap, np->id, s) == NULL) - return soap->error; + if (s) + (void)soap_push_namespace(soap, np->id, s); nq = np; np = np->next; SOAP_FREE(soap, nq); @@ -10472,7 +10922,7 @@ soap_tagsearch(const char *big, const char *little) break; } if (*t == '\0' || *t == ' ') - { if (i == n || (i && little[i-1] == ':')) + { if (i == n || (i > 0 && little[i-1] == ':')) return s; } s = strchr(t, ' '); @@ -10504,9 +10954,10 @@ soap_lookup_ns(struct soap *soap, const char *tag, size_t n) #ifndef WITH_LEAN static struct soap_nlist * -soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized) +soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized, short isearly) { struct soap_nlist *np; size_t n, k; + unsigned int level = soap->level + isearly; if (soap_tagsearch(soap->c14nexclude, id)) return NULL; if (!utilized) @@ -10515,13 +10966,13 @@ soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized) break; } if (np) - { if ((np->level < soap->level || !np->ns) && np->index == 1) + { if ((np->level < level || !np->ns) && np->index == 1) utilized = 1; else return NULL; } } - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Adding namespace binding (level=%u) '%s' '%s' utilized=%d\n", soap->level, id, ns ? ns : "(null)", utilized)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Adding namespace binding (level=%u) '%s' '%s' utilized=%d\n", level, id, ns ? ns : "(null)", utilized)); n = strlen(id); if (ns) k = strlen(ns); @@ -10541,7 +10992,7 @@ soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized) } else np->ns = NULL; - np->level = soap->level; + np->level = level; np->index = utilized; return np; } @@ -10551,25 +11002,36 @@ soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized) #ifndef WITH_LEAN static void -soap_utilize_ns(struct soap *soap, const char *tag) +soap_utilize_ns(struct soap *soap, const char *tag, short isearly) { struct soap_nlist *np; size_t n = 0; - const char *t = strchr(tag, ':'); - if (t) - n = t - tag; + if (!strncmp(tag, "xmlns:", 6)) + { tag += 6; + n = strlen(tag); + } + else + { const char *t = strchr(tag, ':'); + if (t) + n = t - tag; + } np = soap_lookup_ns(soap, tag, n); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Utilizing namespace of '%s'\n", tag)); if (np) - { if (np->index <= 0) - { if (np->level == soap->level) + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Utilizing namespace of '%s' at level %u utilized=%d at level=%u\n", tag, soap->level + isearly, np->index, np->level)); + if (np->index <= 0) + { if (np->level == soap->level + isearly) np->index = 1; else - soap_push_ns(soap, np->id, np->ns, 1); + soap_push_ns(soap, np->id, np->ns, 1, isearly); } } else if (n && strncmp(tag, "xml", 3)) - { soap_strncpy(soap->tmpbuf, sizeof(soap->tmpbuf), tag, n); - soap_push_ns(soap, soap->tmpbuf, NULL, 1); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Utilizing '%s' at level %u\n", tag, soap->level + isearly)); + char *t = (char*)SOAP_MALLOC(soap, n + 1); + if (t) + { (void)soap_strncpy(t, n + 1, tag, n); + soap_push_ns(soap, t, NULL, 1, isearly); + SOAP_FREE(soap, t); + } } } #endif @@ -10586,9 +11048,6 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) const char *s; #endif DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element begin tag='%s' level='%u' id='%d' type='%s'\n", tag, soap->level, id, type ? type : SOAP_STR_EOS)); - soap->level++; - if (soap->level > soap->maxlevel) - return soap->error = SOAP_LEVEL; #ifdef WITH_DOM #ifndef WITH_LEAN if (soap_tagsearch(soap->wsuid, tag)) @@ -10599,6 +11058,13 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) if (soap_set_attr(soap, "wsu:Id", soap->tag, 1)) return soap->error; } +#endif +#endif + soap->level++; + if (soap->level > soap->maxlevel) + return soap->error = SOAP_LEVEL; +#ifdef WITH_DOM +#ifndef WITH_LEAN if ((soap->mode & SOAP_XML_CANONICAL) && !(soap->mode & SOAP_DOM_ASIS)) { if (soap->evlev >= soap->level) soap->evlev = 0; @@ -10608,7 +11074,7 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) for (np = soap->nlist; np; np = np->next) { int p = soap_tagsearch(soap->c14ninclude, np->id) != NULL; if (np->index == 2 || p) - { struct soap_nlist *np1 = soap_push_ns(soap, np->id, np->ns, 1); + { struct soap_nlist *np1 = soap_push_ns(soap, np->id, np->ns, 1, 0); if (np1 && !p) np1->index = 0; } @@ -10620,7 +11086,8 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) if (soap->mode & SOAP_XML_DOM) { struct soap_dom_element *elt = (struct soap_dom_element*)soap_malloc(soap, sizeof(struct soap_dom_element)); if (!elt) - return soap->error; + return soap->error = SOAP_EOM; + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Adding DOM element tag='%s' %p (parent='%s' %p)\n", tag, elt, soap->dom ? soap->dom->name : "(null)", soap->dom)); elt->soap = soap; elt->next = NULL; elt->prnt = soap->dom; @@ -10645,6 +11112,8 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) soap->dom->elts = elt; } soap->dom = elt; + if (!elt->name) + return soap->error = SOAP_EOM; } else { @@ -10660,8 +11129,7 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) soap->body = 1; } if ((soap->mode & SOAP_XML_DEFAULTNS)) - { struct Namespace *ns = soap->local_namespaces; - size_t n = 0; + { size_t n = 0; s = strchr(tag, ':'); if (s) n = s++ - tag; @@ -10671,20 +11139,21 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) || soap_send(soap, s)) return soap->error; if (n) - { if (soap->nlist && !strncmp(soap->nlist->id, tag, n) && !soap->nlist->id[n]) - ns = NULL; + { struct Namespace *ns = soap->local_namespaces; for (; ns && ns->id; ns++) { if (*ns->id && ns->ns && !strncmp(ns->id, tag, n) && !ns->id[n]) - { soap_push_ns(soap, ns->id, ns->out ? ns->out : ns->ns, 0); - if (soap_attribute(soap, "xmlns", ns->out ? ns->out : ns->ns)) - return soap->error; + { if (!soap->nlist || *soap->nlist->id || strcmp(soap->nlist->ns, ns->ns)) + { soap_push_ns(soap, SOAP_STR_EOS, ns->out ? ns->out : ns->ns, 0, 0); + if (soap_attribute(soap, "xmlns", ns->out ? ns->out : ns->ns)) + return soap->error; + } break; } } } - else if (!soap->nlist || *soap->nlist->id) - { soap_push_ns(soap, "", "", 0); - if (soap_attribute(soap, "xmlns", "")) + else if (!soap->nlist || *soap->nlist->id || *soap->nlist->ns) + { soap_push_ns(soap, SOAP_STR_EOS, SOAP_STR_EOS, 0, 0); + if (soap_attribute(soap, "xmlns", SOAP_STR_EOS)) return soap->error; } } @@ -10700,20 +11169,7 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) { struct Namespace *ns = soap->local_namespaces; int k = -1; if (ns) - { -#ifndef WITH_LEAN - if ((soap->mode & SOAP_XML_DEFAULTNS)) - { if (soap->version) - k = 4; /* first four required entries */ - else if (!(soap->mode & SOAP_XML_NOTYPE) || (soap->mode & SOAP_XML_NIL)) - { ns += 2; - k = 2; /* next two entries */ - } - else - k = 0; /* no entries */ - } -#endif - while (k-- && ns->id) + { while (k-- && ns->id) { const char *t = ns->out; if (!t) t = ns->ns; @@ -10729,7 +11185,11 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) soap->ns = 1; /* namespace table control: ns = 0 or 2 to start, then 1 to stop dumping the table */ #ifndef WITH_LEAN if ((soap->mode & SOAP_XML_CANONICAL)) - soap_utilize_ns(soap, tag); + { if ((soap->mode & SOAP_XML_DEFAULTNS)) + soap_utilize_ns(soap, SOAP_STR_EOS, 0); + else + soap_utilize_ns(soap, tag, 0); + } #endif if (id > 0) { (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), sizeof(SOAP_BASEREFNAME) + 20), SOAP_BASEREFNAME "%d", id); @@ -10743,17 +11203,10 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) if (type && *type && !(soap->mode & SOAP_XML_NOTYPE)) { const char *t = type; #ifndef WITH_LEAN - if ((soap->mode & SOAP_XML_DEFAULTNS)) - { t = strchr(type, ':'); - if (t) - t++; - else - t = type; - } - else if ((soap->mode & SOAP_XML_CANONICAL)) - soap_utilize_ns(soap, type); + if ((soap->mode & SOAP_XML_CANONICAL)) + soap_utilize_ns(soap, type, 0); #endif - if (soap->attributes ? soap_set_attr(soap, "xsi:type", t, 1) : soap_attribute(soap, "xsi:type", t)) + if (soap_attribute(soap, "xsi:type", t)) return soap->error; } if (soap->null && soap->position > 0 && soap->version == 1) @@ -10763,7 +11216,7 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) { size_t l = strlen(soap->tmpbuf); (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l - 1, 20), ",%d", soap->positions[i]); } - soap_strncat(soap->tmpbuf, sizeof(soap->tmpbuf), "]", 1); + (void)soap_strncat(soap->tmpbuf, sizeof(soap->tmpbuf), "]", 1); if (soap_attribute(soap, "SOAP-ENC:position", soap->tmpbuf)) return soap->error; } @@ -10793,8 +11246,6 @@ soap_element(struct soap *soap, const char *tag, int id, const char *type) } soap->null = 0; soap->position = 0; - if (soap->event == SOAP_SEC_BEGIN) - soap->event = 0; return SOAP_OK; } #endif @@ -10808,17 +11259,13 @@ SOAP_FMAC2 soap_element_begin_out(struct soap *soap, const char *tag, int id, const char *type) { if (*tag == '-') return SOAP_OK; - if (soap_element(soap, tag, id, type)) - return soap->error; #ifdef WITH_DOM - if (soap_element_start_end_out(soap, NULL)) - return soap->error; if (soap->feltbegout) - return soap->error = soap->feltbegout(soap, tag); - return SOAP_OK; -#else - return soap_element_start_end_out(soap, NULL); + return soap->error = soap->feltbegout(soap, tag, id, type); #endif + if (soap_element(soap, tag, id, type)) + return soap->error; + return soap_element_start_end_out(soap, NULL); } #endif @@ -10951,6 +11398,116 @@ soap_strtoul(const char *s, char **t, int b) /******************************************************************************/ +#ifndef PALM_2 +#ifndef soap_strtoll +SOAP_FMAC1 +LONG64 +SOAP_FMAC2 +soap_strtoll(const char *s, char **t, int b) +{ LONG64 n = 0LL; + int c; + while (*s > 0 && *s <= 32) + s++; + if (b == 10) + { short neg = 0; + if (*s == '-') + { s++; + neg = 1; + } + else if (*s == '+') + s++; + while ((c = *s) && c >= '0' && c <= '9') + { if (n >= 922337203685477580LL && (n > 922337203685477580LL || c >= '8')) + { if (neg && n == 922337203685477580LL && c == '8') + { if (t) + *t = (char*)(s + 1); + return -9223372036854775807LL - 1LL; /* appease compilers that complain */ + } + break; + } + n *= 10LL; + n += c - '0'; + s++; + } + if (neg) + n = -n; + } + else /* assume b == 16 and value is always positive */ + { while ((c = *s)) + { if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + if (n > 0x07FFFFFFFFFFFFFFLL) + break; + n <<= 4; + n += c; + s++; + } + } + if (t) + *t = (char*)s; + return n; +} +#endif +#endif + +/******************************************************************************/ + +#ifndef PALM_2 +#ifndef soap_strtoull +SOAP_FMAC1 +ULONG64 +SOAP_FMAC2 +soap_strtoull(const char *s, char **t, int b) +{ ULONG64 n = 0UL; + int c; + while (*s > 0 && *s <= 32) + s++; + if (b == 10) + { short neg = 0; + if (*s == '-') + { s++; + neg = 1; + } + else if (*s == '+') + s++; + while ((c = *s) && c >= '0' && c <= '9') + { if (n >= 1844674407370955161UL) + break; + n *= 10UL; + n += c - '0'; + s++; + } + if (neg && n > 0UL) + s--; + } + else /* b == 16 */ + { while ((c = *s)) + { if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + if (n > 0x0FFFFFFFFFFFFFFFUL) + break; + n <<= 4; + n += c; + s++; + } + } + if (t) + *t = (char*)s; + return n; +} +#endif +#endif + +/******************************************************************************/ + #ifndef PALM_1 SOAP_FMAC1 int @@ -10968,13 +11525,13 @@ soap_array_begin_out(struct soap *soap, const char *tag, int id, const char *typ } else { const char *s; - s = soap_strrchr(type, '['); + s = strchr(type, '['); if (s && (size_t)(s - type) < sizeof(soap->tmpbuf)) - { soap_strncpy(soap->tmpbuf, sizeof(soap->tmpbuf), type, s - type); + { (void)soap_strncpy(soap->tmpbuf, sizeof(soap->tmpbuf), type, s - type); if (soap_attribute(soap, "SOAP-ENC:itemType", soap->tmpbuf)) return soap->error; s++; - if (*s) + if (*s && *s != ']') { soap_strcpy(soap->tmpbuf, sizeof(soap->tmpbuf), s); soap->tmpbuf[strlen(soap->tmpbuf) - 1] = '\0'; if (soap_attribute(soap, "SOAP-ENC:arraySize", soap->tmpbuf)) @@ -10984,7 +11541,7 @@ soap_array_begin_out(struct soap *soap, const char *tag, int id, const char *typ } #ifndef WITH_LEAN if ((soap->mode & SOAP_XML_CANONICAL)) - soap_utilize_ns(soap, type); + soap_utilize_ns(soap, type, 0); #endif return soap_element_start_end_out(soap, NULL); } @@ -11003,21 +11560,30 @@ soap_element_start_end_out(struct soap *soap, const char *tag) { struct soap_nlist *np; for (tp = soap->attributes; tp; tp = tp->next) { if (tp->visible && *tp->name) - soap_utilize_ns(soap, tp->name); + soap_utilize_ns(soap, tp->name, 0); + } + if (soap->event == SOAP_SEC_BEGIN) + { for (np = soap->nlist; np; np = np->next) + if (soap_tagsearch(soap->c14ninclude, np->id)) + soap_push_ns(soap, np->id, np->ns, 1, 0); + soap->event = 0; + soap->evlev = 0; } for (np = soap->nlist; np; np = np->next) - { if (np->ns && (np->index == 1 || (np->index == 0 && soap->event == SOAP_SEC_BEGIN && soap_tagsearch(soap->c14ninclude, np->id)))) + { if (np->ns && np->index == 1) { if (*(np->id)) (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), strlen(np->id) + 6), "xmlns:%s", np->id); else soap_strcpy(soap->tmpbuf, sizeof(soap->tmpbuf), "xmlns"); - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enabling utilized binding (level=%u) %s='%s' c14ninclude='%s'\n", np->level, soap->tmpbuf, np->ns, soap->c14ninclude ? soap->c14ninclude : "(null)")); - soap_set_attr(soap, soap->tmpbuf, np->ns, 1); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enabling utilized binding (level=%u) %s='%s' SEC-BEGIN=%d c14ninclude='%s'\n", np->level, soap->tmpbuf, np->ns, soap->event == SOAP_SEC_BEGIN, soap->c14ninclude ? soap->c14ninclude : "(null)")); np->index = 2; + soap->level--; + if (soap_set_attr(soap, soap->tmpbuf, np->ns, 1)) + return soap->error; + soap->level++; } else - { - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Binding (level=%u) %s='%s' utilized=%d\n", np->level, np->id, np->ns, np->index)); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Binding (level=%u) %s='%s' utilized=%d\n", np->level, np->id, np->ns, np->index)); } } } @@ -11036,6 +11602,8 @@ soap_element_start_end_out(struct soap *soap, const char *tag) (*att)->name = soap_strdup(soap, tp->name); (*att)->text = soap_strdup(soap, tp->value); (*att)->soap = soap; + if (!(*att)->name || (tp->value && !(*att)->text)) + return soap->error = SOAP_EOM; att = &(*att)->next; tp->visible = 0; } @@ -11087,16 +11655,29 @@ SOAP_FMAC1 int SOAP_FMAC2 soap_element_end_out(struct soap *soap, const char *tag) +{ if (*tag == '-') + return SOAP_OK; +#ifdef WITH_DOM + if (soap->feltendout) + return soap->error = soap->feltendout(soap, tag); +#endif + return soap_element_end(soap, tag); +} +#endif + +/******************************************************************************/ + +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_element_end(struct soap *soap, const char *tag) { #ifndef WITH_LEAN const char *s; #endif - if (*tag == '-') - return SOAP_OK; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element ending tag='%s'\n", tag)); #ifdef WITH_DOM - if (soap->feltendout && (soap->error = soap->feltendout(soap, tag)) != SOAP_OK) - return soap->error; if ((soap->mode & SOAP_XML_DOM) && soap->dom) { if (soap->dom->prnt) soap->dom = soap->dom->prnt; @@ -11123,7 +11704,6 @@ soap_element_end_out(struct soap *soap, const char *tag) return soap_send_raw(soap, ">", 1); } #endif - /******************************************************************************/ #ifndef PALM_1 @@ -11194,6 +11774,19 @@ soap_element_null(struct soap *soap, const char *tag, int id, const char *type) SOAP_FMAC1 int SOAP_FMAC2 +soap_element_empty(struct soap *soap, const char *tag) +{ if (soap_element(soap, tag, -1, NULL)) + return soap->error; + return soap_element_start_end_out(soap, tag); +} +#endif + +/******************************************************************************/ + +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 soap_element_nil(struct soap *soap, const char *tag) { if (soap_element(soap, tag, -1, NULL) || (soap_attribute(soap, "xsi:nil", "true"))) @@ -11216,7 +11809,7 @@ soap_element_id(struct soap *soap, const char *tag, int id, const void *p, const } #ifndef WITH_NOIDREF DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element_id %p type=%d id=%d\n", p, t, id)); - if ((!soap->encodingStyle && !(soap->omode & SOAP_XML_GRAPH)) || (soap->omode & SOAP_XML_TREE)) + if ((!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH)) || (soap->mode & SOAP_XML_TREE)) return soap_check_and_mark(soap, p, t, mark); if (mark) *mark = NULL; @@ -11254,7 +11847,7 @@ SOAP_FMAC2 soap_check_and_mark(struct soap *soap, const void *p, int t, char **mark) { if (mark) { struct soap_plist *pp; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Check %p and mark %p\n", p, mark)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Check %p and mark %p\n", p, (void*)mark)); if (!soap_pointer_lookup(soap, p, t, &pp)) if (!soap_pointer_enter(soap, p, NULL, 0, t, &pp)) return -1; @@ -11398,16 +11991,25 @@ soap_attribute(struct soap *soap, const char *name, const char *value) a->text = soap_strdup(soap, value); a->soap = soap; soap->dom->atts = a; + if (!a->name || (value && !a->text)) + return soap->error = SOAP_EOM; return SOAP_OK; } #endif #ifndef WITH_LEAN if ((soap->mode & SOAP_XML_CANONICAL)) { /* push namespace */ - if (!strncmp(name, "xmlns", 5) && (name[5] == ':' || name[5] == '\0')) - soap_push_ns(soap, name + 5 + (name[5] == ':'), value, 0); - else if (soap_set_attr(soap, name, value, 1)) - return soap->error; + if (!strncmp(name, "xmlns", 5) && ((name[5] == ':') || name[5] == '\0')) + { if (name[5] == ':' && soap->c14ninclude && ((*soap->c14ninclude == '*' || soap_tagsearch(soap->c14ninclude, name + 6)))) + soap_utilize_ns(soap, name, 0); + soap_push_ns(soap, name + 5 + (name[5] == ':'), value, 0, 0); + } + else + { soap->level--; + if (soap_set_attr(soap, name, value, 1)) + return soap->error; + soap->level++; + } } else #endif @@ -11482,7 +12084,7 @@ soap_element_end_in(struct soap *soap, const char *tag) soap->dom = soap->dom->prnt; if ((soap->mode & SOAP_XML_STRICT)) { for (; *s; s++) - if (soap_notblank(*s)) + if (!soap_coblank((soap_wchar)*s)) return soap->error = SOAP_SYNTAX_ERROR; /* reject mixed content before ending tag */ } } @@ -11496,7 +12098,7 @@ soap_element_end_in(struct soap *soap, const char *tag) { while (((c = soap_get(soap)) != SOAP_TT)) { if ((int)c == EOF) return soap->error = SOAP_CHK_EOF; - if (!soap_blank(c)) + if (!soap_coblank(c)) { if ((soap->mode & SOAP_XML_STRICT)) return soap->error = SOAP_SYNTAX_ERROR; /* reject mixed content before ending tag */ if (c == SOAP_LT) @@ -11513,14 +12115,14 @@ soap_element_end_in(struct soap *soap, const char *tag) } while (n--); s = soap->tag; n = sizeof(soap->tag); - while (soap_notblank(c = soap_get(soap))) + while ((c = soap_get(soap)) > 32) { if (--n > 0) *s++ = (char)c; } *s = '\0'; if ((int)c == EOF) return soap->error = SOAP_CHK_EOF; - while (soap_blank(c)) + while (soap_coblank(c)) c = soap_get(soap); if (c != SOAP_GT) return soap->error = SOAP_SYNTAX_ERROR; @@ -11551,7 +12153,7 @@ soap_element_end_in(struct soap *soap, const char *tag) SOAP_FMAC1 const char * SOAP_FMAC2 -soap_attr_value(struct soap *soap, const char *name, int flag) +soap_attr_value(struct soap *soap, const char *name, int flag, int occurs) { struct soap_attribute *tp; if (*name == '-') return SOAP_STR_EOS; @@ -11560,12 +12162,14 @@ soap_attr_value(struct soap *soap, const char *name, int flag) break; } if (tp && tp->visible == 2) - { if (flag == 4 || (flag == 2 && (soap->mode & SOAP_XML_STRICT))) + { if (occurs == 4 || (occurs == 2 && (soap->mode & SOAP_XML_STRICT))) soap->error = SOAP_PROHIBITED; + else if (flag >= 4) + return soap_collapse(soap, tp->value, flag, 1); else return tp->value; } - else if (flag == 3 || (flag == 1 && (soap->mode & SOAP_XML_STRICT))) + else if (occurs == 3 || (occurs == 1 && (soap->mode & SOAP_XML_STRICT))) soap->error = SOAP_REQUIRED; else soap->error = SOAP_OK; @@ -11650,7 +12254,7 @@ soap_set_attr(struct soap *soap, const char *name, const char *value, int flag) { return SOAP_OK; } else if (value && tp->value && tp->size <= strlen(value)) - { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free attribute value of %s (free %p)\n", name, tp->value)); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free attribute value of %s (free %p)\n", name, (void*)tp->value)); SOAP_FREE(soap, tp->value); tp->value = NULL; tp->ns = NULL; @@ -11661,7 +12265,7 @@ soap_set_attr(struct soap *soap, const char *name, const char *value, int flag) tp->value = (char*)SOAP_MALLOC(soap, tp->size); if (!tp->value) return soap->error = SOAP_EOM; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Allocate attribute value for %s (%p)\n", tp->name, tp->value)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Allocate attribute value for %s (%p)\n", tp->name, (void*)tp->value)); } soap_strcpy(tp->value, tp->size, value); if (!strncmp(tp->name, "xmlns:", 6)) @@ -11680,7 +12284,7 @@ soap_set_attr(struct soap *soap, const char *name, const char *value, int flag) if (np && np->ns && soap->local_namespaces) { if ((!strcmp(s + 1, "type") && !strcmp(np->ns, soap->local_namespaces[2].ns)) /* xsi:type QName */ || ((!strcmp(s + 1, "arrayType") || !strcmp(s + 1, "itemType")) && !strcmp(np->ns, soap->local_namespaces[1].ns))) /* SOAP-ENC:arrayType and SOAP-ENC:itemType QName */ - soap_utilize_ns(soap, value); + soap_utilize_ns(soap, value, 1); } } } @@ -11743,14 +12347,19 @@ soap_getattrval(struct soap *soap, char *s, size_t *n, soap_wchar d) if (c < 0x0800) *t++ = (char)(0xC0 | ((c >> 6) & 0x1F)); else - { if (c < 0x010000) - *t++ = (char)(0xE0 | ((c >> 12) & 0x0F)); + { +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + if (!((c >= 0x80 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF))) + c = SOAP_UNKNOWN_UNICODE_CHAR; +#endif + if (c < 0x010000) + *t++ = (char)(0xE0 | ((c >> 12) & 0x0F)); else { if (c < 0x200000) - *t++ = (char)(0xF0 | ((c >> 18) & 0x07)); + *t++ = (char)(0xF0 | ((c >> 18) & 0x07)); else { if (c < 0x04000000) - *t++ = (char)(0xF8 | ((c >> 24) & 0x03)); + *t++ = (char)(0xF8 | ((c >> 24) & 0x03)); else { *t++ = (char)(0xFC | ((c >> 30) & 0x01)); *t++ = (char)(0x80 | ((c >> 24) & 0x3F)); @@ -11937,7 +12546,7 @@ soap_peek_element(struct soap *soap) c = soap_get(soap); #ifdef WITH_DOM /* whitespace leading up to the start tag is significant for DOM as-is (but comments and PIs are removed from this lead) */ - if (soap_blank(c)) + if (soap_coblank(c)) { soap->labidx = 0; do { if (soap_append_lab(soap, NULL, 0)) @@ -11945,17 +12554,17 @@ soap_peek_element(struct soap *soap) s = soap->labbuf + soap->labidx; i = soap->lablen - soap->labidx; soap->labidx = soap->lablen; - while (soap_blank(c) && i--) + while (soap_coblank(c) && i--) { *s++ = c; c = soap_get(soap); } - } while (soap_blank(c)); + } while (soap_coblank(c)); *s = '\0'; lead = soap->labbuf; } #else /* skip space */ - while (soap_blank(c)) + while (soap_coblank(c)) c = soap_get(soap); #endif if (c != SOAP_LT) @@ -11974,17 +12583,18 @@ soap_peek_element(struct soap *soap) #endif return soap->error = SOAP_NO_TAG; } - do c = soap_get1(soap); - while (soap_blank(c)); + do + { c = soap_get1(soap); + } while (soap_coblank(c)); s = soap->tag; i = sizeof(soap->tag); - while (c != '>' && c != '/' && soap_notblank(c) && (int)c != EOF) + while (c != '>' && c != '/' && c > 32 && (int)c != EOF) { if (--i > 0) *s++ = (char)c; c = soap_get1(soap); } *s = '\0'; - while (soap_blank(c)) + while (soap_coblank(c)) c = soap_get1(soap); #ifdef WITH_DOM if (soap->mode & SOAP_XML_DOM) @@ -12020,6 +12630,8 @@ soap_peek_element(struct soap *soap) } soap->dom = elt; att = &elt->atts; + if (!elt->name) + return soap->error = SOAP_EOM; } #endif soap_pop_namespace(soap); @@ -12028,7 +12640,7 @@ soap_peek_element(struct soap *soap) while ((int)c != EOF && c != '>' && c != '/') { s = soap->tmpbuf; i = sizeof(soap->tmpbuf); - while (c != '=' && c != '>' && c != '/' && soap_notblank(c) && (int)c != EOF) + while (c != '=' && c != '>' && c != '/' && c > 32 && (int)c != EOF) { if (--i > 0) *s++ = (char)c; c = soap_get1(soap); @@ -12047,6 +12659,8 @@ soap_peek_element(struct soap *soap) (*att)->name = soap_strdup(soap, soap->tmpbuf); (*att)->text = NULL; (*att)->soap = soap; + if (!(*att)->name) + return soap->error = SOAP_EOM; } #endif if (!strncmp(soap->tmpbuf, "xmlns", 5)) @@ -12083,12 +12697,13 @@ soap_peek_element(struct soap *soap) soap->attributes = tp; } } - while (soap_blank(c)) + while (soap_coblank(c)) c = soap_get1(soap); if (c == '=') { size_t k; - do c = soap_getutf8(soap); - while (soap_blank(c)); + do + { c = soap_getutf8(soap); + } while (soap_coblank(c)); if (c != SOAP_QT && c != SOAP_AP) { soap_unget(soap, c); c = ' '; /* blank delimiter */ @@ -12134,7 +12749,7 @@ soap_peek_element(struct soap *soap) if (soap->error != SOAP_EOM) return soap->error; soap->error = SOAP_OK; - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return soap->error; for (;;) { s = (char*)soap_push_block(soap, NULL, SOAP_BLKLEN); @@ -12163,12 +12778,16 @@ soap_peek_element(struct soap *soap) tp->size = k; #endif } - do c = soap_get1(soap); - while (soap_blank(c)); + do + { c = soap_get1(soap); + } while (soap_coblank(c)); tp->visible = 2; /* seen this attribute w/ value */ #ifdef WITH_DOM - if (att) - (*att)->text = soap_strdup(soap, tp->value); + if (att && tp->value) + { (*att)->text = soap_strdup(soap, tp->value); + if (!(*att)->text) + return soap->error = SOAP_EOM; + } #endif } else @@ -12193,8 +12812,9 @@ soap_peek_element(struct soap *soap) return soap->error = SOAP_CHK_EOF; soap->body = (c != '/'); if (!soap->body) - { do c = soap_get1(soap); - while (soap_blank(c)); + { do + { c = soap_get1(soap); + } while (soap_coblank(c)); } #ifdef WITH_DOM if (soap->mode & SOAP_XML_DOM) @@ -12244,14 +12864,13 @@ soap_peek_element(struct soap *soap) else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:encodingStyle")) { if (!soap->encodingStyle) soap->encodingStyle = SOAP_STR_EOS; - soap_get_version(soap); + soap_version(soap); } else if (soap->version == 1) - { - if (!soap_match_tag(soap, tp->name, "SOAP-ENC:arrayType")) + { if (!soap_match_tag(soap, tp->name, "SOAP-ENC:arrayType")) { s = soap_strrchr(tp->value, '['); if (s && (size_t)(s - tp->value) < sizeof(soap->arrayType)) - { soap_strncpy(soap->arrayType, sizeof(soap->arrayType), tp->value, s - tp->value); + { (void)soap_strncpy(soap->arrayType, sizeof(soap->arrayType), tp->value, s - tp->value); soap_strcpy(soap->arraySize, sizeof(soap->arraySize), s); } else @@ -12399,6 +13018,8 @@ soap_string_out(struct soap *soap, const char *s, int flag) #ifdef WITH_DOM if ((soap->mode & SOAP_XML_DOM) && soap->dom) { soap->dom->text = soap_strdup(soap, s); + if (!soap->dom->text) + return soap->error = SOAP_EOM; return SOAP_OK; } #endif @@ -12515,7 +13136,7 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char if (t + l + 1 >= soap->tmpbuf + sizeof(soap->tmpbuf)) break; /* too many or attribute values to large */ *t++ = ' '; - soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->name, l); + (void)soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->name, l); t += l; if (tp->value) { l = strlen(tp->value); @@ -12523,7 +13144,7 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char break; /* too many or attribute values to large */ *t++ = '='; *t++ = '"'; - soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->value, l); + (void)soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->value, l); t += l; *t++ = '"'; } @@ -12547,7 +13168,7 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char #ifdef WITH_FAST soap->labidx = 0; /* use look-aside buffer */ #else - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; #endif for (;;) @@ -12585,7 +13206,12 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char if (c < 0x0800) *t++ = (char)(0xC0 | ((c >> 6) & 0x1F)); else - { if (c < 0x010000) + { +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + if (!((c >= 0x80 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF))) + c = SOAP_UNKNOWN_UNICODE_CHAR; +#endif + if (c < 0x010000) *t++ = (char)(0xE0 | ((c >> 12) & 0x0F)); else { if (c < 0x200000) @@ -12711,8 +13337,9 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char else if (c == '!') { c = soap_getchar(soap); if (c == '[') - { do c = soap_getchar(soap); - while ((int)c != EOF && c != '['); + { do + { c = soap_getchar(soap); + } while ((int)c != EOF && c != '['); if ((int)c == EOF) goto end; t = (char*)"![CDATA["; @@ -12758,7 +13385,7 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char #ifdef HAVE_WCTOMB if (soap->mode & SOAP_C_MBSTRING) { -#ifdef WIN32 +#if defined(WIN32) && !defined(CYGWIN) && !defined(__MINGW32__) && !defined(__MINGW64__) m = 0; wctomb_s(&m, buf, sizeof(buf), (wchar_t)(c & 0x7FFFFFFF)); #else @@ -12792,7 +13419,7 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char #ifdef WITH_FAST soap->labidx = 0; /* use look-aside buffer */ #else - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; #endif for (;;) @@ -12829,14 +13456,19 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char if (c < 0x0800) *t++ = (char)(0xC0 | ((c >> 6) & 0x1F)); else - { if (c < 0x010000) - *t++ = (char)(0xE0 | ((c >> 12) & 0x0F)); + { +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + if (!((c >= 0x80 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF))) + c = SOAP_UNKNOWN_UNICODE_CHAR; +#endif + if (c < 0x010000) + *t++ = (char)(0xE0 | ((c >> 12) & 0x0F)); else { if (c < 0x200000) - *t++ = (char)(0xF0 | ((c >> 18) & 0x07)); + *t++ = (char)(0xF0 | ((c >> 18) & 0x07)); else { if (c < 0x04000000) - *t++ = (char)(0xF8 | ((c >> 24) & 0x03)); + *t++ = (char)(0xF8 | ((c >> 24) & 0x03)); else { *t++ = (char)(0xFC | ((c >> 30) & 0x01)); *t++ = (char)(0x80 | ((c >> 24) & 0x3F)); @@ -12970,7 +13602,7 @@ soap_string_in(struct soap *soap, int flag, long minlen, long maxlen, const char #ifdef HAVE_WCTOMB if (soap->mode & SOAP_C_MBSTRING) { -#ifdef WIN32 +#if defined(WIN32) && !defined(CYGWIN) && !defined(__MINGW32__) && !defined(__MINGW64__) m = 0; wctomb_s(&m, buf, sizeof(buf), (wchar_t)(c & 0x7FFFFFFF)); #else @@ -13004,6 +13636,8 @@ end: *s = '\0'; #ifdef WITH_FAST t = soap_strdup(soap, soap->labbuf); + if (!t) + return NULL; #else soap_size_block(soap, NULL, i + 1); t = soap_save_block(soap, NULL, NULL, 0); @@ -13025,6 +13659,9 @@ end: { if (soap_s2QName(soap, t, &t, minlen, maxlen, pattern)) return NULL; } + else if (flag >= 4) + { t = soap_collapse(soap, t, flag, 1); + } #ifndef WITH_LEANER else if (pattern && soap->fsvalidate) { soap->error = soap->fsvalidate(soap, pattern, t); @@ -13147,7 +13784,7 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha if (t + l + 1 >= soap->tmpbuf + sizeof(soap->tmpbuf)) break; *t++ = ' '; - soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->name, l); + (void)soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->name, l); t += l; if (tp->value) { l = strlen(tp->value); @@ -13155,7 +13792,7 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha break; *t++ = '='; *t++ = '"'; - soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->value, l); + (void)soap_strncpy(t, sizeof(soap->tmpbuf) - (t - soap->tmpbuf), tp->value, l); t += l; *t++ = '"'; } @@ -13172,7 +13809,7 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha f = 1; soap->peeked = 0; } - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; for (;;) { s = (wchar_t*)soap_push_block(soap, NULL, sizeof(wchar_t)*SOAP_BLKLEN); @@ -13192,23 +13829,23 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha if (n == 0) goto end; n--; - *s++ = '<'; + *s++ = L'<'; soap_unget(soap, '/'); break; case SOAP_LT: if (flag == 3 || (f && n == 0)) goto end; n++; - *s++ = '<'; + *s++ = L'<'; break; case SOAP_GT: - *s++ = '>'; + *s++ = L'>'; break; case SOAP_QT: - *s++ = '"'; + *s++ = L'"'; break; case SOAP_AP: - *s++ = '\''; + *s++ = L'\''; break; case '/': if (n > 0) @@ -13217,29 +13854,29 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha n--; soap_unget(soap, c); } - *s++ = '/'; + *s++ = L'/'; break; case '<': if (flag > 0) - *s++ = (soap_wchar)'<'; + *s++ = L'<'; else - { *s++ = (soap_wchar)'&'; + { *s++ = L'&'; t = (char*)"lt;"; } break; case '>': if (flag > 0) - *s++ = (soap_wchar)'>'; + *s++ = L'>'; else - { *s++ = (soap_wchar)'&'; + { *s++ = (wchar_t)'&'; t = (char*)"gt;"; } break; case '"': if (flag > 0) - *s++ = (soap_wchar)'"'; + *s++ = L'"'; else - { *s++ = (soap_wchar)'&'; + { *s++ = L'&'; t = (char*)"quot;"; } break; @@ -13254,7 +13891,7 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha c = c1; soap_unget(soap, c2); } - *s++ = (wchar_t)c & 0x7FFFFFFF; + *s++ = (wchar_t)(c & 0x7FFFFFFF); } l++; if (maxlen >= 0 && l > maxlen) @@ -13266,7 +13903,7 @@ soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen, const cha } end: soap_unget(soap, c); - *s = '\0'; + *s = L'\0'; soap_size_block(soap, NULL, sizeof(wchar_t) * (i + 1)); if (l < minlen) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "String too short: %ld chars, minlen=%ld\n", l, minlen)); @@ -13274,6 +13911,10 @@ end: return NULL; } s = (wchar_t*)soap_save_block(soap, NULL, NULL, 0); +#ifndef WITH_LEAN + if (flag >= 4) + s = soap_wcollapse(soap, s, flag, 1); +#endif #ifndef WITH_LEANER if (pattern && soap->fwvalidate) { soap->error = soap->fwvalidate(soap, pattern, s); @@ -13325,6 +13966,8 @@ soap_s2int(struct soap *soap, const char *s, int *p) { if (s) { long n; char *r; + if (!*s) + return soap->error = SOAP_EMPTY; #ifndef WITH_NOIO #ifndef WITH_LEAN soap_reset_errno; @@ -13371,14 +14014,18 @@ soap_inint(struct soap *soap, const char *tag, int *p, const char *type, int t) (void)type; #endif p = (int*)soap_id_enter(soap, soap->id, p, t, sizeof(int), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (int*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(int), 0, NULL, NULL); - else if (p) - { if (soap_s2int(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2int(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (int*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(int), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -13418,6 +14065,8 @@ SOAP_FMAC2 soap_s2long(struct soap *soap, const char *s, long *p) { if (s) { char *r; + if (!*s) + return soap->error = SOAP_EMPTY; #ifndef WITH_NOIO #ifndef WITH_LEAN soap_reset_errno; @@ -13460,14 +14109,18 @@ soap_inlong(struct soap *soap, const char *tag, long *p, const char *type, int t (void)type; #endif p = (long*)soap_id_enter(soap, soap->id, p, t, sizeof(long), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (long*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(long), 0, NULL, NULL); - else if (p) - { if (soap_s2long(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2long(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (long*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(long), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -13500,13 +14153,15 @@ soap_outLONG64(struct soap *soap, const char *tag, int id, const LONG64 *p, cons /******************************************************************************/ -#ifndef WITH_LEAN +#ifndef PALM_2 SOAP_FMAC1 int SOAP_FMAC2 soap_s2LONG64(struct soap *soap, const char *s, LONG64 *p) { if (s) { char *r; + if (!*s) + return soap->error = SOAP_EMPTY; #ifndef WITH_NOIO #ifndef WITH_LEAN soap_reset_errno; @@ -13553,14 +14208,18 @@ soap_inLONG64(struct soap *soap, const char *tag, LONG64 *p, const char *type, i } #endif p = (LONG64*)soap_id_enter(soap, soap->id, p, t, sizeof(LONG64), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (LONG64*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(LONG64), 0, NULL, NULL); - else if (p) - { if (soap_s2LONG64(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2LONG64(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (LONG64*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(LONG64), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -13600,6 +14259,8 @@ soap_s2byte(struct soap *soap, const char *s, char *p) { if (s) { long n; char *r; + if (!*s) + return soap->error = SOAP_EMPTY; n = soap_strtol(s, &r, 10); if (s == r || *r || n < -128 || n > 127) soap->error = SOAP_TYPE; @@ -13630,14 +14291,18 @@ soap_inbyte(struct soap *soap, const char *tag, char *p, const char *type, int t (void)type; #endif p = (char*)soap_id_enter(soap, soap->id, p, t, sizeof(char), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (char*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(char), 0, NULL, NULL); - else if (p) - { if (soap_s2byte(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2byte(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (char*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(char), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -13677,6 +14342,8 @@ soap_s2short(struct soap *soap, const char *s, short *p) { if (s) { long n; char *r; + if (!*s) + return soap->error = SOAP_EMPTY; n = soap_strtol(s, &r, 10); if (s == r || *r || n < -32768 || n > 32767) soap->error = SOAP_TYPE; @@ -13708,14 +14375,18 @@ soap_inshort(struct soap *soap, const char *tag, short *p, const char *type, int (void)type; #endif p = (short*)soap_id_enter(soap, soap->id, p, t, sizeof(short), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (short*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(short), 0, NULL, NULL); - else if (p) - { if (soap_s2short(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2short(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (short*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(short), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -13728,7 +14399,11 @@ const char* SOAP_FMAC2 soap_float2s(struct soap *soap, float n) { -#if !defined(WITH_C_LOCALE) || !defined(HAVE_SPRINTF_L) +#if defined(WITH_C_LOCALE) +# if !defined(WIN32) + SOAP_LOCALE_T locale; +# endif +#else char *s; #endif if (soap_isnan((double)n)) @@ -13737,11 +14412,13 @@ soap_float2s(struct soap *soap, float n) return "INF"; if (soap_isninff(n)) return "-INF"; -#if defined(WITH_C_LOCALE) && defined(HAVE_SPRINTF_L) +#if defined(WITH_C_LOCALE) # ifdef WIN32 _sprintf_s_l(soap->tmpbuf, _countof(soap->tmpbuf), soap->float_format, SOAP_LOCALE(soap), n); # else - sprintf_l(soap->tmpbuf, SOAP_LOCALE(soap), soap->float_format, n); + locale = uselocale(SOAP_LOCALE(soap)); + (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), 20), soap->float_format, n); + uselocale(locale); # endif #else (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), 20), soap->float_format, n); @@ -13776,7 +14453,7 @@ SOAP_FMAC2 soap_s2float(struct soap *soap, const char *s, float *p) { if (s) { if (!*s) - return soap->error = SOAP_TYPE; + return soap->error = SOAP_EMPTY; if (!soap_tag_cmp(s, "INF")) *p = FLT_PINFTY; else if (!soap_tag_cmp(s, "+INF")) @@ -13787,36 +14464,61 @@ soap_s2float(struct soap *soap, const char *s, float *p) *p = FLT_NAN; else { -/* On some systems strtof requires -std=c99 or does not even link: so we try to use strtod first */ -#if defined(WITH_C_LOCALE) && defined(HAVE_STRTOD_L) +/* On some systems strtof requires -std=c99 or does not even link: so we try strtod first */ +#if defined(WITH_C_LOCALE) +# if defined(HAVE_STRTOD_L) char *r; -# ifdef WIN32 +# ifdef WIN32 *p = (float)_strtod_l(s, &r, SOAP_LOCALE(soap)); -# else +# else *p = (float)strtod_l(s, &r, SOAP_LOCALE(soap)); -# endif +# endif if (*r) soap->error = SOAP_TYPE; -#elif defined(HAVE_STRTOD) +# elif defined(HAVE_STRTOF_L) char *r; - *p = (float)strtod(s, &r); + *p = strtof_l((char*)s, &r, SOAP_LOCALE(soap)); if (*r) soap->error = SOAP_TYPE; -#elif defined(WITH_C_LOCALE) && defined(HAVE_STRTOF_L) +# elif defined(HAVE_SSCANF_L) + double n; + if (sscanf_l(s, SOAP_LOCALE(soap), "%lf", &n) != 1) + soap->error = SOAP_TYPE; + *p = (float)n; +# elif defined(HAVE_STRTOD) char *r; - *p = strtof_l((char*)s, &r, SOAP_LOCALE(soap)); + SOAP_LOCALE_T locale = uselocale(SOAP_LOCALE(soap)); + *p = (float)strtod((char*)s, &r); + uselocale(locale); if (*r) soap->error = SOAP_TYPE; -#elif defined(HAVE_STRTOF) +# elif defined(HAVE_STRTOF) char *r; + SOAP_LOCALE_T locale = uselocale(SOAP_LOCALE(soap)); *p = strtof((char*)s, &r); + uselocale(locale); if (*r) soap->error = SOAP_TYPE; -#elif defined(WITH_C_LOCALE) && defined(HAVE_SSCANF_L) && !defined(HAVE_STRTOF_L) && !defined(HAVE_STRTOD_L) +# elif defined(HAVE_SSCANF) double n; - if (sscanf_l(s, SOAP_LOCALE(soap), "%lf", &n) != 1) + SOAP_LOCALE_T locale = uselocale(SOAP_LOCALE(soap)); + if (sscanf(s, "%lf", &n) != 1) soap->error = SOAP_TYPE; + uselocale(locale); *p = (float)n; +# else + soap->error = SOAP_TYPE; +# endif +#elif defined(HAVE_STRTOD) + char *r; + *p = (float)strtod(s, &r); + if (*r) + soap->error = SOAP_TYPE; +#elif defined(HAVE_STRTOF) + char *r; + *p = strtof((char*)s, &r); + if (*r) + soap->error = SOAP_TYPE; #elif defined(HAVE_SSCANF) double n; if (sscanf(s, "%lf", &n) != 1) @@ -13876,14 +14578,18 @@ soap_infloat(struct soap *soap, const char *tag, float *p, const char *type, int (void)type; #endif p = (float*)soap_id_enter(soap, soap->id, p, t, sizeof(float), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (float*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(float), 0, NULL, NULL); - else if (p) - { if (soap_s2float(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2float(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (float*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(float), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -13896,7 +14602,11 @@ const char* SOAP_FMAC2 soap_double2s(struct soap *soap, double n) { -#if !defined(WITH_C_LOCALE) || !defined(HAVE_SPRINTF_L) +#if defined(WITH_C_LOCALE) +# if !defined(WIN32) + SOAP_LOCALE_T locale; +# endif +#else char *s; #endif if (soap_isnan(n)) @@ -13905,11 +14615,13 @@ soap_double2s(struct soap *soap, double n) return "INF"; if (soap_isninfd(n)) return "-INF"; -#if defined(WITH_C_LOCALE) && defined(HAVE_SPRINTF_L) +#if defined(WITH_C_LOCALE) # ifdef WIN32 _sprintf_s_l(soap->tmpbuf, _countof(soap->tmpbuf), soap->double_format, SOAP_LOCALE(soap), n); # else - sprintf_l(soap->tmpbuf, SOAP_LOCALE(soap), soap->double_format, n); + locale = uselocale(SOAP_LOCALE(soap)); + (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), 40), soap->double_format, n); + uselocale(locale); # endif #else (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), 40), soap->double_format, n); @@ -13944,7 +14656,7 @@ SOAP_FMAC2 soap_s2double(struct soap *soap, const char *s, double *p) { if (s) { if (!*s) - return soap->error = SOAP_TYPE; + return soap->error = SOAP_EMPTY; if (!soap_tag_cmp(s, "INF")) *p = DBL_PINFTY; else if (!soap_tag_cmp(s, "+INF")) @@ -13955,23 +14667,36 @@ soap_s2double(struct soap *soap, const char *s, double *p) *p = DBL_NAN; else { -#if defined(WITH_C_LOCALE) && defined(HAVE_STRTOD_L) +#if defined(WITH_C_LOCALE) +# if defined(HAVE_STRTOD_L) char *r; -# ifdef WIN32 +# ifdef WIN32 *p = _strtod_l(s, &r, SOAP_LOCALE(soap)); -# else +# else *p = strtod_l(s, &r, SOAP_LOCALE(soap)); -# endif +# endif if (*r) soap->error = SOAP_TYPE; -#elif defined(HAVE_STRTOD) +# elif defined(HAVE_STRTOD) char *r; + SOAP_LOCALE_T locale = uselocale(SOAP_LOCALE(soap)); *p = strtod(s, &r); + uselocale(locale); if (*r) soap->error = SOAP_TYPE; -#elif defined(WITH_C_LOCALE) && defined(HAVE_SSCANF_L) && !defined(HAVE_STRTOF_L) && !defined(HAVE_STRTOD_L) +# elif defined(HAVE_SSCANF_L) + SOAP_LOCALE_T locale = uselocale(SOAP_LOCALE(soap)); if (sscanf_l(s, SOAP_LOCALE(soap), "%lf", p) != 1) soap->error = SOAP_TYPE; + uselocale(locale); +# else + soap->error = SOAP_TYPE; +# endif +#elif defined(HAVE_STRTOD) + char *r; + *p = strtod(s, &r); + if (*r) + soap->error = SOAP_TYPE; #elif defined(HAVE_SSCANF) if (sscanf(s, "%lf", p) != 1) soap->error = SOAP_TYPE; @@ -14000,14 +14725,18 @@ soap_indouble(struct soap *soap, const char *tag, double *p, const char *type, i (void)type; #endif p = (double*)soap_id_enter(soap, soap->id, p, t, sizeof(double), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (double*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(double), 0, NULL, NULL); - else if (p) - { if (soap_s2double(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2double(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (double*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(double), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -14047,6 +14776,8 @@ soap_s2unsignedByte(struct soap *soap, const char *s, unsigned char *p) { if (s) { long n; char *r; + if (!*s) + return soap->error = SOAP_EMPTY; n = soap_strtol(s, &r, 10); if (s == r || *r || n < 0 || n > 255) soap->error = SOAP_TYPE; @@ -14077,14 +14808,18 @@ soap_inunsignedByte(struct soap *soap, const char *tag, unsigned char *p, const (void)type; #endif p = (unsigned char*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned char), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (unsigned char*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned char), 0, NULL, NULL); - else if (p) - { if (soap_s2unsignedByte(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2unsignedByte(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (unsigned char*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned char), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -14124,6 +14859,8 @@ soap_s2unsignedShort(struct soap *soap, const char *s, unsigned short *p) { if (s) { long n; char *r; + if (!*s) + return soap->error = SOAP_EMPTY; n = soap_strtol(s, &r, 10); if (s == r || *r || n < 0 || n > 65535) soap->error = SOAP_TYPE; @@ -14155,14 +14892,18 @@ soap_inunsignedShort(struct soap *soap, const char *tag, unsigned short *p, cons (void)type; #endif p = (unsigned short*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned short), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (unsigned short*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned short), 0, NULL, NULL); - else if (p) - { if (soap_s2unsignedShort(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2unsignedShort(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (unsigned short*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned short), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -14201,6 +14942,8 @@ SOAP_FMAC2 soap_s2unsignedInt(struct soap *soap, const char *s, unsigned int *p) { if (s) { char *r; + if (!*s) + return soap->error = SOAP_EMPTY; #ifndef WITH_NOIO #ifndef WITH_LEAN soap_reset_errno; @@ -14247,14 +14990,18 @@ soap_inunsignedInt(struct soap *soap, const char *tag, unsigned int *p, const ch (void)type; #endif p = (unsigned int*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned int), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (unsigned int*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned int), 0, NULL, NULL); - else if (p) - { if (soap_s2unsignedInt(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2unsignedInt(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (unsigned int*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned int), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -14294,6 +15041,8 @@ SOAP_FMAC2 soap_s2unsignedLong(struct soap *soap, const char *s, unsigned long *p) { if (s) { char *r; + if (!*s) + return soap->error = SOAP_EMPTY; #ifndef WITH_NOIO #ifndef WITH_LEAN soap_reset_errno; @@ -14340,14 +15089,18 @@ soap_inunsignedLong(struct soap *soap, const char *tag, unsigned long *p, const (void)type; #endif p = (unsigned long*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned long), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (unsigned long*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned long), 0, NULL, NULL); - else if (p) - { if (soap_s2unsignedLong(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2unsignedLong(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (unsigned long*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(unsigned long), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -14387,6 +15140,8 @@ SOAP_FMAC2 soap_s2ULONG64(struct soap *soap, const char *s, ULONG64 *p) { if (s) { char *r; + if (!*s) + return soap->error = SOAP_EMPTY; #ifndef WITH_NOIO #ifndef WITH_LEAN soap_reset_errno; @@ -14430,14 +15185,18 @@ soap_inULONG64(struct soap *soap, const char *tag, ULONG64 *p, const char *type, return NULL; } p = (ULONG64*)soap_id_enter(soap, soap->id, p, t, sizeof(ULONG64), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (ULONG64*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(ULONG64), 0, NULL, NULL); - else if (p) - { if (soap_s2ULONG64(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2ULONG64(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (ULONG64*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(ULONG64), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -14448,9 +15207,9 @@ soap_inULONG64(struct soap *soap, const char *tag, ULONG64 *p, const char *type, SOAP_FMAC1 int SOAP_FMAC2 -soap_s2char(struct soap *soap, const char *s, char **t, long minlen, long maxlen, const char *pattern) +soap_s2char(struct soap *soap, const char *s, char **t, int flag, long minlen, long maxlen, const char *pattern) { if (s) - { const char *r = soap_string(soap, s, minlen, maxlen, pattern); + { const char *r = soap_string(soap, s, flag, minlen, maxlen, pattern); if (r && (*t = soap_strdup(soap, r)) == NULL) return soap->error = SOAP_EOM; } @@ -14466,9 +15225,9 @@ soap_s2char(struct soap *soap, const char *s, char **t, long minlen, long maxlen SOAP_FMAC1 int SOAP_FMAC2 -soap_s2stdchar(struct soap *soap, const char *s, std::string *t, long minlen, long maxlen, const char *pattern) +soap_s2stdchar(struct soap *soap, const char *s, std::string *t, int flag, long minlen, long maxlen, const char *pattern) { if (s) - { const char *r = soap_string(soap, s, minlen, maxlen, pattern); + { const char *r = soap_string(soap, s, flag, minlen, maxlen, pattern); if (r) t->assign(r); } @@ -14482,7 +15241,7 @@ soap_s2stdchar(struct soap *soap, const char *s, std::string *t, long minlen, lo #ifndef PALM_2 static const char* -soap_string(struct soap *soap, const char *s, long minlen, long maxlen, const char *pattern) +soap_string(struct soap *soap, const char *s, int flag, long minlen, long maxlen, const char *pattern) { if (s) { if (maxlen < 0 && soap->maxlength > 0) maxlen = soap->maxlength; @@ -14497,6 +15256,8 @@ soap_string(struct soap *soap, const char *s, long minlen, long maxlen, const ch return NULL; } } + if (flag >= 4) + s = soap_collapse(soap, (char*)s, flag, 0); #ifndef WITH_LEANER if (pattern && soap->fsvalidate) { soap->error = soap->fsvalidate(soap, pattern, s); @@ -14514,6 +15275,62 @@ soap_string(struct soap *soap, const char *s, long minlen, long maxlen, const ch /******************************************************************************/ #ifndef PALM_2 +static char* +soap_collapse(struct soap *soap, char *s, int flag, int insitu) +{ /* flag 4=normalizedString (replace), 5=token (collapse) */ + char *t; + size_t n; + if (flag == 4) + { for (t = s; *t && (!soap_coblank((soap_wchar)*t) || *t == 32); t++) + continue; + if (*t) + { /* replace blanks and control char by space */ + if (!insitu) + s = soap_strdup(soap, s); + for (t = s; *t; t++) + if (soap_coblank((soap_wchar)*t)) + *t = ' '; + } + return s; + } + /* collapse white space */ + for (t = s; *t && soap_coblank((soap_wchar)*t); t++) + continue; + n = strlen(t); + if (insitu && s < t) + soap_memmove(s, n + 1, t, n + 1); + else + s = t; + if (n > 0) + { if (!soap_coblank((soap_wchar)s[n-1])) + { for (t = s; (*t && !soap_coblank((soap_wchar)*t)) || (*t == 32 && (!t[1] || !soap_coblank((soap_wchar)t[1]))); t++) + continue; + if (!*t) + return s; + } + if (!insitu) + s = soap_strdup(soap, s); + for (t = s; *t; t++) + { if (soap_coblank((soap_wchar)*t)) + { char *r; + *t = ' '; + for (r = t + 1; *r && soap_coblank((soap_wchar)*r); r++) + continue; + if (r > t + 1) + soap_memmove(t + 1, n - (t-s), r, n - (r-s) + 1); + } + } + t--; + if (t >= s && *t == 32) + *t = '\0'; + } + return s; +} +#endif + +/******************************************************************************/ + +#ifndef PALM_2 SOAP_FMAC1 int SOAP_FMAC2 @@ -14570,7 +15387,7 @@ soap_QName(struct soap *soap, const char *s, long minlen, long maxlen, const cha #ifdef WITH_FAST soap->labidx = 0; #else - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; #endif DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Normalized namespace(s) of QNames '%s'", s)); @@ -14586,13 +15403,13 @@ soap_QName(struct soap *soap, const char *s, long minlen, long maxlen, const cha size_t k = 0; #endif /* skip blanks */ - while (*s && soap_blank((soap_wchar)*s)) + while (*s && soap_coblank((soap_wchar)*s)) s++; if (!*s) break; /* find next QName */ n = 1; - while (s[n] && !soap_blank((soap_wchar)s[n])) + while (s[n] && !soap_coblank((soap_wchar)s[n])) n++; np = soap->nlist; /* if there is no namespace stack, or prefix is "#" or "xml" then copy string */ @@ -14682,7 +15499,7 @@ soap_QName(struct soap *soap, const char *s, long minlen, long maxlen, const cha #endif /* advance to next and add spacing */ s += n; - while (*s && soap_blank(*s)) + while (*s && soap_coblank(*s)) s++; if (*s) { @@ -14734,7 +15551,7 @@ soap_QName2s(struct soap *soap, const char *s) soap->labidx = 0; #else char *b = NULL; - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; #endif for (;;) @@ -14746,12 +15563,12 @@ soap_QName2s(struct soap *soap, const char *s) size_t k = 0; #endif /* skip blanks */ - while (*s && soap_blank((soap_wchar)*s)) + while (*s && soap_coblank((soap_wchar)*s)) s++; if (!*s) { #ifdef WITH_FAST - soap->labbuf[soap->labidx > 0 ? soap->labidx - 1 : 0] = '\0'; + soap->labbuf[soap->labidx > 0 ? soap->labidx - 1 : 0] = '\0'; #else if (!b) return soap_strdup(soap, SOAP_STR_EOS); @@ -14762,37 +15579,29 @@ soap_QName2s(struct soap *soap, const char *s) } /* find next QName */ n = 0; - while (s[n] && !soap_blank((soap_wchar)s[n])) + while (s[n] && !soap_coblank((soap_wchar)s[n])) n++; /* normal prefix: pass string as is */ if (*s != '"') { #ifndef WITH_LEAN if ((soap->mode & SOAP_XML_CANONICAL)) - soap_utilize_ns(soap, s); - if ((soap->mode & SOAP_XML_DEFAULTNS)) - { r = strchr(s, ':'); - if (r && soap->nlist && !strncmp(soap->nlist->id, s, r - s) && !soap->nlist->id[r - s]) - { n -= r - s + 1; - s = r + 1; - } - } + soap_utilize_ns(soap, s, 1); #endif r = s; m = n + 1; } else /* URL-based string prefix */ - { s++; - q = strchr(s, '"'); + { q = strchr(s + 1, '"'); if (q) { struct Namespace *p = soap->local_namespaces; if (p) { for (; p->id; p++) { if (p->ns) - if (!soap_tag_cmp(s, p->ns)) + if (!soap_tag_cmp(s + 1, p->ns)) break; if (p->in) - if (!soap_tag_cmp(s, p->in)) + if (!soap_tag_cmp(s + 1, p->in)) break; } } @@ -14800,16 +15609,13 @@ soap_QName2s(struct soap *soap, const char *s) /* URL is in the namespace table? */ if (p && p->id) { r = p->id; -#ifndef WITH_LEAN - if ((soap->mode & SOAP_XML_DEFAULTNS) && soap->nlist && !strcmp(soap->nlist->id, r)) - q++; - else -#endif - m = strlen(r); + m = strlen(r); } else /* not in namespace table: create xmlns binding */ - { char *x = soap_strdup(soap, s); - x[q - s - 1] = '\0'; + { char *x = soap_strdup(soap, s + 1); + if (!x) + return NULL; + x[q - s - 2] = '\0'; (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), 27), "xmlns:_%d", soap->idnum++); soap_set_attr(soap, soap->tmpbuf, x, 1); r = soap->tmpbuf + 6; @@ -14820,10 +15626,10 @@ soap_QName2s(struct soap *soap, const char *s) /* copy normalized QName into buffer, including the ending blank or NUL */ #ifdef WITH_FAST if ((m && soap_append_lab(soap, r, m)) - || (q && soap_append_lab(soap, q, n - (q - s)))) + || (q && soap_append_lab(soap, q, n - (q - s) + 1))) return NULL; #else - k = m + (q ? n - (q - s) : 0); + k = m + (q ? n - (q - s) + 1 : 0); b = (char*)soap_push_block(soap, NULL, k); if (!b) { soap->error = SOAP_EOM; @@ -14835,11 +15641,11 @@ soap_QName2s(struct soap *soap, const char *s) } b += m; if (q) - { if (soap_memcpy((void*)b, k - m, (const void*)q, n - (q - s))) + { if (soap_memcpy((void*)b, k - m, (const void*)q, n - (q - s) + 1)) { soap->error = SOAP_EOM; return NULL; } - b += n - (q - s); + b += n - (q - s) + 1; } #endif /* advance to next */ @@ -14847,6 +15653,8 @@ soap_QName2s(struct soap *soap, const char *s) } #ifdef WITH_FAST t = soap_strdup(soap, soap->labbuf); + if (!t) + soap->error = SOAP_EOM; #else t = (char*)soap_save_block(soap, NULL, NULL, 0); #endif @@ -14861,9 +15669,9 @@ soap_QName2s(struct soap *soap, const char *s) SOAP_FMAC1 int SOAP_FMAC2 -soap_s2wchar(struct soap *soap, const char *s, wchar_t **t, long minlen, long maxlen, const char *pattern) +soap_s2wchar(struct soap *soap, const char *s, wchar_t **t, int flag, long minlen, long maxlen, const char *pattern) { if (s) - { const wchar_t *r = soap_wstring(soap, s, minlen, maxlen, pattern); + { const wchar_t *r = soap_wstring(soap, s, flag, minlen, maxlen, pattern); if (r && (*t = soap_wstrdup(soap, r)) == NULL) return soap->error = SOAP_EOM; } @@ -14879,9 +15687,9 @@ soap_s2wchar(struct soap *soap, const char *s, wchar_t **t, long minlen, long ma SOAP_FMAC1 int SOAP_FMAC2 -soap_s2stdwchar(struct soap *soap, const char *s, std::wstring *t, long minlen, long maxlen, const char *pattern) +soap_s2stdwchar(struct soap *soap, const char *s, std::wstring *t, int flag, long minlen, long maxlen, const char *pattern) { if (s) - { const wchar_t *r = soap_wstring(soap, s, minlen, maxlen, pattern); + { const wchar_t *r = soap_wstring(soap, s, flag, minlen, maxlen, pattern); if (r) t->assign(r); } @@ -14895,10 +15703,10 @@ soap_s2stdwchar(struct soap *soap, const char *s, std::wstring *t, long minlen, #ifndef WITH_LEAN static const wchar_t* -soap_wstring(struct soap *soap, const char *s, long minlen, long maxlen, const char *pattern) +soap_wstring(struct soap *soap, const char *s, int flag, long minlen, long maxlen, const char *pattern) { if (s) { long l; - wchar_t wc; + wchar_t wc, *t; if (maxlen < 0 && soap->maxlength > 0) maxlen = soap->maxlength; soap->labidx = 0; @@ -14913,31 +15721,62 @@ soap_wstring(struct soap *soap, const char *s, long minlen, long maxlen, const c else { /* Convert UTF8 to wchar */ while (*s) - { soap_wchar c, c1, c2, c3, c4; + { soap_wchar c; c = (unsigned char)*s++; if (c < 0x80) wc = (wchar_t)c; else - { c1 = (soap_wchar)*s++ & 0x3F; + { +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + soap_wchar c1, c2, c3; + c1 = (unsigned char)*s++; + if (c <= 0xC1 || (c1 & 0xC0) != 0x80) + wc = SOAP_UNKNOWN_UNICODE_CHAR; + else + { c1 &= 0x3F; + if (c < 0xE0) + wc = (((c & 0x1F) << 6) | c1); + else + { c2 = (unsigned char)*s++; + if ((c == 0xE0 && c1 < 0x20) || (c2 & 0xC0) != 0x80) + wc = SOAP_UNKNOWN_UNICODE_CHAR; + else + { c2 &= 0x3F; + if (c < 0xF0) + wc = (((c & 0x0F) << 12) | (c1 << 6) | c2); + else + { c3 = (unsigned char)*s++; + if ((c == 0xF0 && c1 < 0x10) || (c == 0xF4 && c1 >= 0x10) || c >= 0xF5 || (c3 & 0xC0) != 0x80) + wc = SOAP_UNKNOWN_UNICODE_CHAR; + else + wc = (((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | (c3 & 0x3F)); + } + } + } + } +#else + soap_wchar c1, c2, c3, c4; + c1 = (unsigned char)*s++ & 0x3F; if (c < 0xE0) wc = (wchar_t)(((soap_wchar)(c & 0x1F) << 6) | c1); else - { c2 = (soap_wchar)*s++ & 0x3F; + { c2 = (unsigned char)*s++ & 0x3F; if (c < 0xF0) wc = (wchar_t)(((soap_wchar)(c & 0x0F) << 12) | (c1 << 6) | c2); else - { c3 = (soap_wchar)*s++ & 0x3F; + { c3 = (unsigned char)*s++ & 0x3F; if (c < 0xF8) wc = (wchar_t)(((soap_wchar)(c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3); else - { c4 = (soap_wchar)*s++ & 0x3F; + { c4 = (unsigned char)*s++ & 0x3F; if (c < 0xFC) wc = (wchar_t)(((soap_wchar)(c & 0x03) << 24) | (c1 << 18) | (c2 << 12) | (c3 << 6) | c4); else - wc = (wchar_t)(((soap_wchar)(c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | (soap_wchar)(*s++ & 0x3F)); + wc = (wchar_t)(((soap_wchar)(c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | (unsigned char)(*s++ & 0x3F)); } } } +#endif } if (soap_append_lab(soap, (const char*)&wc, sizeof(wc))) return NULL; @@ -14951,14 +15790,19 @@ soap_wstring(struct soap *soap, const char *s, long minlen, long maxlen, const c { soap->error = SOAP_LENGTH; return NULL; } + t = (wchar_t*)soap->labbuf; +#ifndef WITH_LEAN + if (flag >= 4) + t = soap_wcollapse(soap, t, flag, 1); +#endif #ifndef WITH_LEANER if (pattern && soap->fwvalidate) - { soap->error = soap->fwvalidate(soap, pattern, (wchar_t*)soap->labbuf); + { soap->error = soap->fwvalidate(soap, pattern, t); if (soap->error) return NULL; } #endif - return (wchar_t*)soap->labbuf; + return t; } return NULL; } @@ -14967,6 +15811,66 @@ soap_wstring(struct soap *soap, const char *s, long minlen, long maxlen, const c /******************************************************************************/ #ifndef WITH_LEAN +#ifndef PALM_2 +static wchar_t* +soap_wcollapse(struct soap *soap, wchar_t *s, int flag, int insitu) +{ /* flag 4=normalizedString (replace), 5=token (collapse) */ + wchar_t *t; + size_t n; + if (flag == 4) + { for (t = s; *t && (!soap_coblank((soap_wchar)*t) || *t == 32); t++) + continue; + if (*t) + { /* replace blanks and control char by space */ + if (!insitu) + s = soap_wstrdup(soap, s); + for (t = s; *t; t++) + if (soap_coblank((soap_wchar)*t)) + *t = L' '; + } + return s; + } + /* collapse white space */ + for (t = s; *t && soap_coblank((soap_wchar)*t); t++) + continue; + n = 0; + while (t[n]) + n++; + if (insitu && s < t) + soap_memmove(s, n + 1, t, n + 1); + else + s = t; + if (n > 0) + { if (!soap_coblank((soap_wchar)s[n-1])) + { for (t = s; (*t && !soap_coblank((soap_wchar)*t)) || (*t == 32 && (!t[1] || !soap_coblank((soap_wchar)t[1]))); t++) + continue; + if (!*t) + return s; + } + if (!insitu) + s = soap_wstrdup(soap, s); + for (t = s; *t; t++) + { if (soap_coblank((soap_wchar)*t)) + { wchar_t *r; + *t = L' '; + for (r = t + 1; *r && soap_coblank((soap_wchar)*r); r++) + continue; + if (r > t + 1) + soap_memmove(t + 1, sizeof(wchar_t) * (n - (t-s)), r, sizeof(wchar_t) * (n - (r-s) + 1)); + } + } + t--; + if (t >= s && *t == 32) + *t = L'\0'; + } + return s; +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_LEAN SOAP_FMAC1 const char* SOAP_FMAC2 @@ -14981,19 +15885,29 @@ soap_wchar2s(struct soap *soap, const wchar_t *s) { if (c > 0 && c < 0x80) n++; else +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + n += 4; +#else n += 6; +#endif } r = t = (char*)soap_malloc(soap, n + 1); if (r) - { /* Convert wchar to UTF8 */ + { /* Convert wchar to UTF8 (chars above U+10FFFF are silently converted, but should not be used) */ while ((c = *s++)) { if (c > 0 && c < 0x80) *t++ = (char)c; else - { if (c < 0x0800) + { + if (c < 0x0800) *t++ = (char)(0xC0 | ((c >> 6) & 0x1F)); else - { if (c < 0x010000) + { +#ifdef WITH_REPLACE_ILLEGAL_UTF8 + if (!((c >= 0x80 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF))) + c = SOAP_UNKNOWN_UNICODE_CHAR; +#endif + if (c < 0x010000) *t++ = (char)(0xE0 | ((c >> 12) & 0x0F)); else { if (c < 0x200000) @@ -15073,14 +15987,16 @@ soap_instring(struct soap *soap, const char *tag, char **p, const char *type, in { soap->error = SOAP_NO_TAG; return NULL; } - else if (!*soap->href) + else if (*soap->href != '#') { if (minlen > 0) { soap->error = SOAP_LENGTH; return NULL; } *p = soap_strdup(soap, SOAP_STR_EOS); + if (!*p) + return NULL; } - if (*soap->href) + if (*soap->href == '#') p = (char**)soap_id_lookup(soap, soap->href, (void**)p, t, sizeof(char**), 0, NULL); if (soap->body && soap_element_end_in(soap, tag)) return NULL; @@ -15117,7 +16033,7 @@ soap_outwstring(struct soap *soap, const char *tag, int id, wchar_t *const*p, co SOAP_FMAC1 wchar_t ** SOAP_FMAC2 -soap_inwstring(struct soap *soap, const char *tag, wchar_t **p, const char *type, int t, long minlen, long maxlen, const char *pattern) +soap_inwstring(struct soap *soap, const char *tag, wchar_t **p, const char *type, int t, int flag, long minlen, long maxlen, const char *pattern) { (void)type; if (soap_element_begin_in(soap, tag, 1, NULL)) { if (!tag || *tag != '-' || soap->error != SOAP_NO_TAG) @@ -15132,7 +16048,7 @@ soap_inwstring(struct soap *soap, const char *tag, wchar_t **p, const char *type if (soap->null) *p = NULL; else if (soap->body) - { *p = soap_wstring_in(soap, 1, minlen, maxlen, pattern); + { *p = soap_wstring_in(soap, flag, minlen, maxlen, pattern); if (!*p || !(wchar_t*)soap_id_enter(soap, soap->id, *p, t, sizeof(wchar_t*), NULL, NULL, NULL, NULL)) return NULL; if (!**p && tag && *tag == '-') @@ -15144,14 +16060,14 @@ soap_inwstring(struct soap *soap, const char *tag, wchar_t **p, const char *type { soap->error = SOAP_NO_TAG; return NULL; } - else if (!*soap->href) + else if (*soap->href != '#') { if (minlen > 0) { soap->error = SOAP_LENGTH; return NULL; } *p = soap_wstrdup(soap, L""); } - if (*soap->href) + if (*soap->href == '#') p = (wchar_t**)soap_id_lookup(soap, soap->href, (void**)p, t, sizeof(wchar_t**), 0, NULL); if (soap->body && soap_element_end_in(soap, tag)) return NULL; @@ -15407,6 +16323,8 @@ soap_s2dateTime(struct soap *soap, const char *s, time_t *p) { char *t; unsigned long d; struct tm T; + if (!*s) + return soap->error = SOAP_EMPTY; memset((void*)&T, 0, sizeof(T)); d = soap_strtoul(s, &t, 10); if (*t == '-') @@ -15525,14 +16443,18 @@ soap_indateTime(struct soap *soap, const char *tag, time_t *p, const char *type, return NULL; } p = (time_t*)soap_id_enter(soap, soap->id, p, t, sizeof(time_t), NULL, NULL, NULL, NULL); - if (*soap->href) - p = (time_t*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(time_t), 0, NULL, NULL); - else if (p) - { if (soap_s2dateTime(soap, soap_value(soap), p)) + if (!p) + return NULL; + if (*soap->href != '#') + { int err = soap_s2dateTime(soap, soap_value(soap), p); + if ((soap->body && soap_element_end_in(soap, tag)) || err) + return NULL; + } + else + { p = (time_t*)soap_id_forward(soap, soap->href, p, 0, t, t, sizeof(time_t), 0, NULL, NULL); + if (soap->body && soap_element_end_in(soap, tag)) return NULL; } - if (soap->body && soap_element_end_in(soap, tag)) - return NULL; return p; } #endif @@ -15678,8 +16600,9 @@ soap_value(struct soap *soap) char *s = soap->tmpbuf; if (!soap->body) return SOAP_STR_EOS; - do c = soap_get(soap); - while (soap_blank(c)); + do + { c = soap_get(soap); + } while (soap_coblank(c)); for (i = 0; i < sizeof(soap->tmpbuf) - 1; i++) { if (c == SOAP_TT || c == SOAP_LT || (int)c == EOF) break; @@ -15687,7 +16610,7 @@ soap_value(struct soap *soap) c = soap_get(soap); } for (s--; i > 0; i--, s--) - { if (!soap_blank((soap_wchar)*s)) + { if (!soap_coblank((soap_wchar)*s)) break; } s[1] = '\0'; @@ -15701,7 +16624,10 @@ soap_value(struct soap *soap) } #ifdef WITH_DOM if ((soap->mode & SOAP_XML_DOM) && soap->dom) - soap->dom->text = soap_strdup(soap, soap->tmpbuf); + { soap->dom->text = soap_strdup(soap, soap->tmpbuf); + if (!soap->dom->text) + return NULL; + } #endif return soap->tmpbuf; /* return non-null pointer */ } @@ -15916,7 +16842,7 @@ soap_putdime(struct soap *soap) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimereadopen failed\n")); return soap->error; } - if (!size && ((soap->mode & SOAP_ENC_XML) || (soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_IO) == SOAP_IO_STORE)) + if (!size && ((soap->mode & SOAP_ENC_PLAIN) || (soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_IO) == SOAP_IO_STORE)) { size_t chunksize = sizeof(soap->tmpbuf); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunked streaming DIME\n")); do @@ -15964,7 +16890,7 @@ soap_putdime(struct soap *soap) } while (size); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimereadclose\n")); if (soap_send_raw(soap, SOAP_STR_PADDING, -(long)soap->dime.size&3)) - return soap->error; + return soap->error; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimereadclose\n")); if (soap->fdimereadclose) @@ -16142,7 +17068,7 @@ end: id = soap->dime.id; type = soap->dime.type; options = soap->dime.options; - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return SOAP_EOM; for (;;) { soap_wchar c; @@ -16179,7 +17105,7 @@ end: } else soap->dime.ptr = soap_getdimefield(soap, soap->dime.size); - content = soap_new_multipart(soap, &soap->dime.first, &soap->dime.last, soap->dime.ptr, soap->dime.size); + content = soap_alloc_multipart(soap, &soap->dime.first, &soap->dime.last, soap->dime.ptr, soap->dime.size); if (!content) return soap->error = SOAP_EOM; content->id = soap->dime.id; @@ -16213,7 +17139,7 @@ soap_getmimehdr(struct soap *soap) if (soap->msgbuf[0] == '-' && soap->msgbuf[1] == '-') { char *s = soap->msgbuf + strlen(soap->msgbuf) - 1; /* remove white space */ - while (soap_blank((soap_wchar)*s)) + while (soap_coblank((soap_wchar)*s)) s--; s[1] = '\0'; if (soap->mime.boundary) @@ -16221,7 +17147,10 @@ soap_getmimehdr(struct soap *soap) return soap->error = SOAP_MIME_ERROR; } else - soap->mime.boundary = soap_strdup(soap, soap->msgbuf + 2); + { soap->mime.boundary = soap_strdup(soap, soap->msgbuf + 2); + if (!soap->mime.boundary) + return soap->error = SOAP_EOM; + } if (soap_getline(soap, soap->msgbuf, sizeof(soap->msgbuf))) return soap->error; } @@ -16237,14 +17166,15 @@ soap_getmimehdr(struct soap *soap) val = strchr(soap->msgbuf, ':'); if (val) { *val = '\0'; - do val++; - while (*val && *val <= 32); + do + { val++; + } while (*val && *val <= 32); if (!soap_tag_cmp(key, "Content-ID")) content->id = soap_strdup(soap, val); else if (!soap_tag_cmp(key, "Content-Location")) content->location = soap_strdup(soap, val); else if (!content->id && !soap_tag_cmp(key, "Content-Disposition")) - content->id = soap_strdup(soap, soap_get_header_attribute(soap, val, "name")); + content->id = soap_strdup(soap, soap_http_header_attribute(soap, val, "name")); else if (!soap_tag_cmp(key, "Content-Type")) content->type = soap_strdup(soap, val); else if (!soap_tag_cmp(key, "Content-Description")) @@ -16319,7 +17249,7 @@ soap_get_mime_attachment(struct soap *soap, void *handle) if (!(soap->mode & SOAP_ENC_MIME)) return NULL; content = soap->mime.last; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get MIME (%p)\n", content)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get MIME (%p)\n", (void*)content)); if (!content) { if (soap_getmimehdr(soap)) return NULL; @@ -16332,14 +17262,13 @@ soap_get_mime_attachment(struct soap *soap, void *handle) } } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Parsing MIME content id='%s' type='%s'\n", content->id ? content->id : SOAP_STR_EOS, content->type ? content->type : SOAP_STR_EOS)); - if (!content->ptr && soap_new_block(soap) == NULL) + if (!content->ptr && soap_alloc_block(soap) == NULL) { soap->error = SOAP_EOM; return NULL; } for (;;) { if (content->ptr) - { - s = soap->tmpbuf; + { s = soap->tmpbuf; } else { s = (char*)soap_push_block(soap, NULL, sizeof(soap->tmpbuf)); @@ -16367,10 +17296,15 @@ soap_get_mime_attachment(struct soap *soap, void *handle) { memset((void*)soap->msgbuf, 0, sizeof(soap->msgbuf)); soap_strcpy(soap->msgbuf, sizeof(soap->msgbuf), "\n--"); if (soap->mime.boundary) - soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), soap->mime.boundary, sizeof(soap->msgbuf) - 4); + { if (soap_strncat(soap->msgbuf, sizeof(soap->msgbuf), soap->mime.boundary, sizeof(soap->msgbuf) - 4)) + { soap->error = SOAP_MIME_ERROR; + return NULL; + } + } t = soap->msgbuf; - do c = soap_getchar(soap); - while (c == *t++); + do + { c = soap_getchar(soap); + } while (c == *t++); if ((int)c == EOF) { if (content->ptr && soap->fmimewriteclose) soap->fmimewriteclose(soap, (void*)content->ptr); @@ -16412,14 +17346,14 @@ end: if (c == '-' && soap_getchar(soap) == '-') { soap->mode &= ~SOAP_ENC_MIME; if ((soap->mode & SOAP_MIME_POSTCHECK) && soap_end_recv(soap)) - { if (soap->keep_alive < 0) + { if (soap->keep_alive == -2) /* special case to keep alive */ soap->keep_alive = 0; soap_closesock(soap); return NULL; } } else - { while (c != '\r' && (int)c != EOF && soap_blank(c)) + { while (c != '\r' && (int)c != EOF && soap_coblank(c)) c = soap_getchar(soap); if (c != '\r' || soap_getchar(soap) != '\n') { soap->error = SOAP_MIME_ERROR; @@ -16465,6 +17399,50 @@ soap_match_cid(struct soap *soap, const char *s, const char *t) /******************************************************************************/ +/* return UUID "<prefix>xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" in a temporary buffer */ +#ifndef PALM_1 +SOAP_FMAC1 +const char* +SOAP_FMAC2 +soap_rand_uuid(struct soap *soap, const char *prefix) +{ + int r1, r2, r3, r4; +#ifdef WITH_OPENSSL + r1 = soap_random; + r2 = soap_random; +#else + size_t i; + static int k = 0xFACEB00C; + int lo = k % 127773; + int hi = k / 127773; +# if defined(HAVE_GETTIMEOFDAY) + struct timeval tv; + gettimeofday(&tv, NULL); + r1 = 10000000 * tv.tv_sec + tv.tv_usec; +# elif defined(UNDER_CE) + r1 = (int)Random(); +# elif !defined(WITH_LEAN) + r1 = (int)time(NULL); +# else + r1 = k; +# endif + k = 16807 * lo - 2836 * hi; + if (k <= 0) + k += 0x7FFFFFFF; + r2 = k; + k &= 0x8FFFFFFF; + for (i = 0; i < (sizeof(soap->buf) < 16UL ? sizeof(soap->buf) : 16UL); i++) + r2 += soap->buf[i]; +#endif + r3 = soap_random; + r4 = soap_random; + (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), prefix ? strlen(prefix) + 37 : 37), "%s%8.8x-%4.4hx-4%3.3hx-%4.4hx-%4.4hx%8.8x", prefix ? prefix : SOAP_STR_EOS, r1, (short)(r2 >> 16), (short)(((short)r2 >> 4) & 0x0FFF), (short)(((short)(r3 >> 16) & 0x3FFF) | 0x8000), (short)r3, r4); + return soap->tmpbuf; +} +#endif + +/******************************************************************************/ + #ifndef WITH_LEANER #ifndef PALM_1 static void @@ -16545,7 +17523,7 @@ soap_putmime(struct soap *soap) if (soap_putmimehdr(soap, content)) return soap->error; if (!size) - { if ((soap->mode & SOAP_ENC_XML) || (soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_IO) == SOAP_IO_STORE) + { if ((soap->mode & SOAP_ENC_PLAIN) || (soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_IO) == SOAP_IO_STORE) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunked streaming MIME\n")); do { size = soap->fmimeread(soap, handle, soap->tmpbuf, sizeof(soap->tmpbuf)); @@ -16659,9 +17637,9 @@ soap_clr_mime(struct soap *soap) #ifndef WITH_LEANER #ifndef PALM_1 static struct soap_multipart* -soap_new_multipart(struct soap *soap, struct soap_multipart **first, struct soap_multipart **last, char *ptr, size_t size) +soap_alloc_multipart(struct soap *soap, struct soap_multipart **first, struct soap_multipart **last, char *ptr, size_t size) { struct soap_multipart *content; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New MIME attachment %p (%lu)\n", ptr, (unsigned long)size)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New DIME/MIME attachment %p (%lu)\n", (void*)ptr, (unsigned long)size)); content = (struct soap_multipart*)soap_malloc(soap, sizeof(struct soap_multipart)); if (content) { content->next = NULL; @@ -16692,7 +17670,7 @@ SOAP_FMAC1 int SOAP_FMAC2 soap_set_dime_attachment(struct soap *soap, char *ptr, size_t size, const char *type, const char *id, unsigned short optype, const char *option) -{ struct soap_multipart *content = soap_new_multipart(soap, &soap->dime.first, &soap->dime.last, ptr, size); +{ struct soap_multipart *content = soap_alloc_multipart(soap, &soap->dime.first, &soap->dime.last, ptr, size); if (!content) return SOAP_EOM; content->id = soap_strdup(soap, id); @@ -16711,7 +17689,7 @@ SOAP_FMAC1 int SOAP_FMAC2 soap_set_mime_attachment(struct soap *soap, char *ptr, size_t size, enum soap_mime_encoding encoding, const char *type, const char *id, const char *location, const char *description) -{ struct soap_multipart *content = soap_new_multipart(soap, &soap->mime.first, &soap->mime.last, ptr, size); +{ struct soap_multipart *content = soap_alloc_multipart(soap, &soap->mime.first, &soap->mime.last, ptr, size); if (!content) return SOAP_EOM; content->id = soap_strdup(soap, id); @@ -16825,13 +17803,13 @@ soap_getgziphdr(struct soap *soap) } if (f & 0x08) /* skip FNAME */ { do - c = soap_get1(soap); - while (c && (int)c != EOF); + { c = soap_get1(soap); + } while (c && (int)c != EOF); } if ((int)c != EOF && (f & 0x10)) /* skip FCOMMENT */ { do - c = soap_get1(soap); - while (c && (int)c != EOF); + { c = soap_get1(soap); + } while (c && (int)c != EOF); } if ((int)c != EOF && (f & 0x02)) /* skip FHCRC (CRC32 is used) */ { c = soap_get1(soap); @@ -16886,7 +17864,7 @@ int SOAP_FMAC2 soap_begin_recv(struct soap *soap) { soap_wchar c; - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing for input from socket=%d/fd=%d\n", soap->socket, soap->recvfd)); + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing for input from socket=%d/fd=%d\n", (int)soap->socket, soap->recvfd)); soap->error = SOAP_OK; #ifndef WITH_LEANER soap->recverror = SOAP_OK; @@ -16967,6 +17945,9 @@ soap_begin_recv(struct soap *soap) if (soap->ssl) ERR_clear_error(); #endif +#ifndef WITH_LEAN + soap->start = time(NULL); +#endif #ifndef WITH_LEANER if (soap->fprepareinitrecv && (soap->error = soap->fprepareinitrecv(soap)) != SOAP_OK) return soap->error; @@ -17001,7 +17982,7 @@ soap_begin_recv(struct soap *soap) c = ' '; } #endif - while (soap_blank(c)) + while (soap_coblank(c)) c = soap_getchar(soap); #ifndef WITH_LEANER if (c == '-' && soap_get0(soap) == '-') @@ -17025,7 +18006,7 @@ soap_begin_recv(struct soap *soap) || (c == 0xFF && soap_get0(soap) == 0xFE)) /* UTF-16 LE */ return soap->error = SOAP_UTF_ERROR; /* skip space */ - while (soap_blank(c)) + while (soap_coblank(c)) c = soap_getchar(soap); } if ((int)c == EOF) @@ -17033,7 +18014,7 @@ soap_begin_recv(struct soap *soap) soap_unget(soap, c); #ifndef WITH_NOHTTP /* if not XML/MIME/DIME/ZLIB, assume HTTP method or status line */ - if (((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) && !(soap->mode & (SOAP_ENC_MIME | SOAP_ENC_DIME | SOAP_ENC_ZLIB | SOAP_ENC_XML))) + if (((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) && !(soap->mode & (SOAP_ENC_MIME | SOAP_ENC_DIME | SOAP_ENC_ZLIB | SOAP_ENC_PLAIN))) { soap_mode m = soap->imode; soap->mode &= ~SOAP_IO; soap->error = soap->fparse(soap); @@ -17124,12 +18105,14 @@ soap_begin_recv(struct soap *soap) return soap->error = soap->status; /* client side received HTTP status code */ } if (soap->error) - { if (soap->error == SOAP_FORM && soap->fform) - { soap->error = soap->fform(soap); - if (soap->error == SOAP_OK) - soap->error = SOAP_STOP; /* prevents further processing */ - } - return soap->error; + { if (soap->error != SOAP_FORM || !soap->fform) + return soap->error; + soap->error = soap->fform(soap); + if (soap->error == SOAP_OK) + return soap->error = SOAP_STOP; /* prevents further processing */ + if (soap->error < 300) /* continue only if POST plugin returned HTTP error, e.g. not found */ + return soap->error; + soap->error = SOAP_OK; } } #endif @@ -17151,7 +18134,7 @@ soap_begin_recv(struct soap *soap) break; } while (soap_get_mime_attachment(soap, NULL)); } - if (soap_get_header_attribute(soap, soap->mime.first->type, "application/dime")) + if (soap_http_header_attribute(soap, soap->mime.first->type, "application/dime")) soap->mode |= SOAP_ENC_DIME; } if (soap->mode & SOAP_ENC_DIME) @@ -17236,7 +18219,7 @@ soap_envelope_end_out(struct soap *soap) { soap->dime.size = soap->count - soap->dime.size; /* DIME in MIME correction */ (SOAP_SNPRINTF(soap->id, sizeof(soap->id), strlen(soap->dime_id_format) + 20), soap->dime_id_format, 0); soap->dime.id = soap->id; - if (soap->local_namespaces) + if (soap->local_namespaces && soap->local_namespaces[0].id) { if (soap->local_namespaces[0].out) soap->dime.type = (char*)soap->local_namespaces[0].out; else @@ -17280,7 +18263,7 @@ soap_get_http_body(struct soap *soap, size_t *len) #ifdef WITH_FAST soap->labidx = 0; /* use look-aside buffer */ #else - if (soap_new_block(soap) == NULL) + if (soap_alloc_block(soap) == NULL) return NULL; #endif for (;;) @@ -17351,7 +18334,7 @@ soap_envelope_begin_in(struct soap *soap) soap->error = soap->status; return soap->error; } - soap_get_version(soap); + soap_version(soap); return SOAP_OK; } #endif @@ -17493,12 +18476,12 @@ soap_set_endpoint(struct soap *soap, const char *endpoint) soap->passwd = SOAP_STR_EOS; if (*s == ':') { s++; - if (*s != '@') - { l = t - s + 1; - r = r + strlen(r) + 1; - s = soap_decode(r, l, s, "@"); - soap->passwd = r; - } + if (*s != '@') + { l = t - s + 1; + r = r + strlen(r) + 1; + s = soap_decode(r, l, s, "@"); + soap->passwd = r; + } } } s++; @@ -17543,6 +18526,11 @@ soap_set_endpoint(struct soap *soap, const char *endpoint) } if (i < n && s[i]) soap_strcpy(soap->path, sizeof(soap->path), s + i); + if (soap->override_host && *soap->override_host) + { soap_strcpy(soap->host, sizeof(soap->host), soap->override_host); + if (soap->override_port) + soap->port = soap->override_port; + } if (soap->userid && !soap->authrealm) soap->authrealm = soap->host; } @@ -17550,6 +18538,79 @@ soap_set_endpoint(struct soap *soap, const char *endpoint) /******************************************************************************/ +#ifndef WITH_NOHTTP +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_GET(struct soap *soap, const char *endpoint, const char *action) +{ return soap_connect_command(soap, SOAP_GET, endpoint, action); +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_NOHTTP +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_PUT(struct soap *soap, const char *endpoint, const char *action, const char *type) +{ soap_mode omode = soap->omode; + int err; + soap->http_content = type; + if ((omode & SOAP_IO) != SOAP_IO_CHUNK) + { soap->omode &= ~SOAP_IO; + soap->omode |= SOAP_IO_STORE; + } + err = soap_connect_command(soap, SOAP_PUT, endpoint, action); + soap->omode = omode; + return err; +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_NOHTTP +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_POST(struct soap *soap, const char *endpoint, const char *action, const char *type) +{ soap_mode omode = soap->omode; + int err; + soap->http_content = type; + if ((omode & SOAP_IO) != SOAP_IO_CHUNK) + { soap->omode &= ~SOAP_IO; + soap->omode |= SOAP_IO_STORE; + } + err = soap_connect_command(soap, SOAP_POST_FILE, endpoint, action); + soap->omode = omode; + return err; +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_NOHTTP +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_DELETE(struct soap *soap, const char *endpoint) +{ if (soap_connect_command(soap, SOAP_DEL, endpoint, NULL) + || soap_recv_empty_response(soap)) + return soap_closesock(soap); + return SOAP_OK; +} +#endif +#endif + +/******************************************************************************/ + #ifndef PALM_1 SOAP_FMAC1 int @@ -17573,7 +18634,7 @@ soap_connect_command(struct soap *soap, int http_command, const char *endpoints, { size_t l = strlen(endpoints); char *endpoint = (char*)SOAP_MALLOC(soap, l + 1); for (;;) - { soap_strncpy(endpoint, l + 1, endpoints, s - endpoints); + { (void)soap_strncpy(endpoint, l + 1, endpoints, s - endpoints); endpoint[s - endpoints] = '\0'; if (soap_try_connect_command(soap, http_command, endpoint, action) != SOAP_TCP_ERROR) break; @@ -17633,9 +18694,12 @@ soap_try_connect_command(struct soap *soap, int http_command, const char *endpoi DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connect/reconnect to '%s' host='%s' path='%s' port=%d\n", endpoint?endpoint:"(null)", soap->host, soap->path, soap->port)); if (!soap->keep_alive || !soap_valid_socket(soap->socket)) { soap->socket = soap->fopen(soap, endpoint, soap->host, soap->port); - if (soap->error) - return soap->error; - soap->keep_alive = ((soap->omode & SOAP_IO_KEEPALIVE) != 0); + if (!soap_valid_socket(soap->socket) || soap->error) + { if (soap->error) + return soap->error; + return soap->error = SOAP_TCP_ERROR; + } + soap->keep_alive = -((soap->omode & SOAP_IO_KEEPALIVE) != 0); } } } @@ -17651,20 +18715,18 @@ soap_try_connect_command(struct soap *soap, int http_command, const char *endpoi soap->mode |= SOAP_IO_BUFFER; } #ifndef WITH_NOHTTP - if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_XML) && endpoint) - { unsigned int k = soap->mode; + if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_PLAIN) && endpoint) + { soap_mode k = soap->mode; soap->mode &= ~(SOAP_IO | SOAP_ENC_ZLIB); if ((k & SOAP_IO) != SOAP_IO_FLUSH) soap->mode |= SOAP_IO_BUFFER; soap->error = soap->fpost(soap, endpoint, soap->host, soap->port, soap->path, action, count); if (soap->error) return soap->error; -#ifndef WITH_LEANER if ((k & SOAP_IO) == SOAP_IO_CHUNK) { if (soap_flush(soap)) return soap->error; } -#endif soap->mode = k; } if (http_command == SOAP_GET || http_command == SOAP_DEL) @@ -17688,7 +18750,7 @@ soap_ntlm_handshake(struct soap *soap, int command, const char *endpoint, const { tSmbNtlmAuthRequest req; tSmbNtlmAuthResponse res; tSmbNtlmAuthChallenge ch; - short k = soap->keep_alive; + int k = soap->keep_alive; size_t l = soap->length; size_t c = soap->count; soap_mode m = soap->mode, o = soap->omode; @@ -17710,7 +18772,8 @@ soap_ntlm_handshake(struct soap *soap, int command, const char *endpoint, const soap->omode = SOAP_IO_BUFFER; if (soap_begin_send(soap)) return soap->error; - soap->keep_alive = 1; + if (!soap->keep_alive) + soap->keep_alive = -1; /* client keep alive */ soap->status = command; if (soap->fpost(soap, endpoint, host, port, soap->path, soap->action, 0) || soap_end_send_flush(soap)) @@ -17863,7 +18926,7 @@ soap_base642s(struct soap *soap, const char *s, char *t, size_t l, int *n) m = (m << 6) + b; j++; } - else if (!soap_blank(c + '+')) + else if (!soap_coblank(c + '+')) { soap->error = SOAP_TYPE; return NULL; } @@ -17955,24 +19018,22 @@ soap_hex2s(struct soap *soap, const char *s, char *t, size_t l, int *n) #ifndef WITH_NOHTTP #ifndef PALM_1 SOAP_FMAC1 -int +const char * SOAP_FMAC2 -soap_puthttphdr(struct soap *soap, int status, size_t count) +soap_http_content_type(struct soap *soap, int status) { if (soap->status != SOAP_GET && soap->status != SOAP_DEL && soap->status != SOAP_CONNECT) { const char *s = "text/xml; charset=utf-8"; - int err = SOAP_OK; #ifndef WITH_LEANER const char *r = NULL; size_t n; #endif - if ((status == SOAP_FILE || soap->status == SOAP_PUT || soap->status == SOAP_POST_FILE) && soap->http_content && !strchr(s, 10) && !strchr(s, 13)) + if ((status == SOAP_FILE || soap->status == SOAP_PUT || soap->status == SOAP_POST_FILE) && soap->http_content && !strchr(soap->http_content, 10) && !strchr(soap->http_content, 13)) s = soap->http_content; else if (status == SOAP_HTML) s = "text/html; charset=utf-8"; - else if (count || ((soap->omode & SOAP_IO) == SOAP_IO_CHUNK)) - { if (soap->version == 2) - s = "application/soap+xml; charset=utf-8"; - } + else if (soap->version == 2) + s = "application/soap+xml; charset=utf-8"; + soap->http_content = NULL; /* use http_content once (assign new value before each call) */ #ifndef WITH_LEANER if (soap->mode & (SOAP_ENC_DIME | SOAP_ENC_MTOM)) { if (soap->mode & SOAP_ENC_MTOM) @@ -17988,8 +19049,7 @@ soap_puthttphdr(struct soap *soap, int status, size_t count) if ((soap->mode & SOAP_ENC_MIME) && soap->mime.boundary) { const char *t; size_t l; - n = strlen(soap->mime.boundary); - (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), n + 53), "multipart/related; charset=utf-8; boundary=\"%s\"; type=\"", soap->mime.boundary); + (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), strlen(soap->mime.boundary) + 53), "multipart/related; charset=utf-8; boundary=\"%s\"; type=\"", soap->mime.boundary); t = strchr(s, ';'); if (t) n = t - s; @@ -17997,30 +19057,48 @@ soap_puthttphdr(struct soap *soap, int status, size_t count) n = strlen(s); l = strlen(soap->tmpbuf); if (sizeof(soap->tmpbuf) - l > n) - soap_strncpy(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, s, n); + (void)soap_strncpy(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, s, n); if (soap->mime.start) { l = strlen(soap->tmpbuf); - n = strlen(soap->mime.start); - (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, n + 10), "\"; start=\"%s", soap->mime.start); + (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, strlen(soap->mime.start) + 10), "\"; start=\"%s", soap->mime.start); } if (r) { l = strlen(soap->tmpbuf); - n = strlen(r); - (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, n + 15), "\"; start-info=\"%s", r); + (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, strlen(r) + 15), "\"; start-info=\"%s", r); } l = strlen(soap->tmpbuf); if (sizeof(soap->tmpbuf) - l > 1) - soap_strncpy(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, "\"", 1); + (void)soap_strncpy(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, "\"", 1); } else - soap_strcpy(soap->tmpbuf, sizeof(soap->tmpbuf), s); + { soap_strcpy(soap->tmpbuf, sizeof(soap->tmpbuf), s); + } if (status == SOAP_OK && soap->version == 2 && soap->action) { size_t l = strlen(soap->tmpbuf); n = strlen(soap->action); (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, n + 11), "; action=\"%s\"", soap->action); } +#else + soap_strcpy(soap->tmpbuf, sizeof(soap->tmpbuf), s); #endif - err = soap->fposthdr(soap, "Content-Type", soap->tmpbuf); + return soap->tmpbuf; + } + return NULL; +} +#endif +#endif + +/******************************************************************************/ + +#ifndef WITH_NOHTTP +#ifndef PALM_1 +SOAP_FMAC1 +int +SOAP_FMAC2 +soap_puthttphdr(struct soap *soap, int status, size_t count) +{ int err = SOAP_OK; + if (soap_http_content_type(soap, status)) + { err = soap->fposthdr(soap, "Content-Type", soap->tmpbuf); if (err) return err; #ifdef WITH_ZLIB @@ -18046,7 +19124,28 @@ soap_puthttphdr(struct soap *soap, int status, size_t count) if (err) return err; } - return soap->fposthdr(soap, "Connection", soap->keep_alive ? "keep-alive" : "close"); + if (soap->http_extra_header) + { err = soap_send(soap, soap->http_extra_header); + soap->http_extra_header = NULL; /* use http_extra_header once (assign new value before each call) */ + if (err) + return err; + err = soap_send_raw(soap, "\r\n", 2); + if (err) + return err; + } + if (soap->keep_alive) + { if (soap->keep_alive > 0 && soap->recv_timeout) + { int t = soap->recv_timeout; + if (t < 0) + t = 1; + (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), 20), "timeout=%d, max=%d", soap->recv_timeout, soap->keep_alive); + err = soap->fposthdr(soap, "Keep-Alive", soap->tmpbuf); + if (err) + return err; + } + return soap->fposthdr(soap, "Connection", "keep-alive"); + } + return soap->fposthdr(soap, "Connection", "close"); } #endif #endif @@ -18083,7 +19182,7 @@ soap_set_fault(struct soap *soap) else if (soap->version == 1) *c = "SOAP-ENV:Client"; else - *c = "at source"; + *c = "in message exchange"; } if (*s) return; @@ -18102,6 +19201,8 @@ soap_set_fault(struct soap *soap) case SOAP_TYPE: if (*soap->type) *s = soap_set_validation_fault(soap, "type mismatch ", soap->type); + else if (*soap->arrayType) + *s = soap_set_validation_fault(soap, "array type mismatch", NULL); else *s = soap_set_validation_fault(soap, "invalid value", NULL); break; @@ -18250,7 +19351,13 @@ soap_set_fault(struct soap *soap) *s = soap_set_validation_fault(soap, "value range or content length violation", NULL); break; case SOAP_OCCURS: - *s = soap_set_validation_fault(soap, "occurrence constraint violation or maxoccurs exceeded", NULL); + *s = soap_set_validation_fault(soap, "occurrence constraint violation", NULL); + break; + case SOAP_FIXED: + *s = soap_set_validation_fault(soap, "value does not match the fixed value required", NULL); + break; + case SOAP_EMPTY: + *s = soap_set_validation_fault(soap, "empty value provided where a value is required", NULL); break; case SOAP_FD_EXCEEDED: *s = "Maximum number of open connections was reached: increase FD_SETSIZE or define HAVE_POLL"; @@ -18311,6 +19418,10 @@ soap_send_fault(struct soap *soap) { int status = soap->error; if (status == SOAP_OK || status == SOAP_STOP) return soap_closesock(soap); +#ifndef WITH_NOHTTP + if (status >= 200 && status < 300) + return soap_send_empty_response(soap, status); +#endif DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Sending back fault struct for error code %d\n", soap->error)); soap->keep_alive = 0; /* to terminate connection */ soap_set_fault(soap); @@ -18336,29 +19447,50 @@ soap_send_fault(struct soap *soap) #endif if (r > 0) { soap->error = SOAP_OK; - soap->encodingStyle = NULL; /* no encodingStyle in Faults */ - soap_serializeheader(soap); - soap_serializefault(soap); - (void)soap_begin_count(soap); - if (soap->mode & SOAP_IO_LENGTH) - { if (soap_envelope_begin_out(soap) + if (soap->local_namespaces[0].id && soap->local_namespaces[0].ns && soap->local_namespaces[1].id && soap->local_namespaces[1].ns) + { soap->encodingStyle = NULL; /* no encodingStyle in Faults */ + soap_serializeheader(soap); + soap_serializefault(soap); + (void)soap_begin_count(soap); + if (soap->mode & SOAP_IO_LENGTH) + { if (soap_envelope_begin_out(soap) + || soap_putheader(soap) + || soap_body_begin_out(soap) + || soap_putfault(soap) + || soap_body_end_out(soap) + || soap_envelope_end_out(soap)) + return soap_closesock(soap); + } + (void)soap_end_count(soap); + if (soap_response(soap, status) + || soap_envelope_begin_out(soap) || soap_putheader(soap) || soap_body_begin_out(soap) || soap_putfault(soap) || soap_body_end_out(soap) - || soap_envelope_end_out(soap)) - return soap_closesock(soap); + || soap_envelope_end_out(soap) + || soap_end_send(soap)) + return soap_closesock(soap); + } + else + { const char *s = *soap_faultstring(soap); + const char **d = soap_faultdetail(soap); + (void)soap_begin_count(soap); + if (soap->mode & SOAP_IO_LENGTH) + if (soap_element_begin_out(soap, "fault", 0, NULL) + || soap_outstring(soap, "reason", 0, (char*const*)&s, NULL, 0) + || soap_outliteral(soap, "detail", (char*const*)d, NULL) + || soap_element_end_out(soap, "fault")) + return soap_closesock(soap); + (void)soap_end_count(soap); + if (soap_response(soap, status) + || soap_element_begin_out(soap, "fault", 0, NULL) + || soap_outstring(soap, "reason", 0, (char*const*)&s, NULL, 0) + || soap_outliteral(soap, "detail", (char*const*)d, NULL) + || soap_element_end_out(soap, "fault") + || soap_end_send(soap)) + return soap_closesock(soap); } - (void)soap_end_count(soap); - if (soap_response(soap, status) - || soap_envelope_begin_out(soap) - || soap_putheader(soap) - || soap_body_begin_out(soap) - || soap_putfault(soap) - || soap_body_end_out(soap) - || soap_envelope_end_out(soap) - || soap_end_send(soap)) - return soap_closesock(soap); } } soap->error = status; @@ -18379,11 +19511,10 @@ soap_recv_fault(struct soap *soap, int check) { /* try getfault when no tag or tag mismatched at level 2, otherwise ret */ if (soap->error != SOAP_NO_TAG && (soap->error != SOAP_TAG_MISMATCH || soap->level != 2)) - return soap->error; + return soap_closesock(soap); } else if (soap->version == 0) /* check == 1 but no SOAP: do not parse SOAP Fault */ - { - DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Not a SOAP protocol\n")); + { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Not a SOAP protocol\n")); return SOAP_OK; } soap->error = SOAP_OK; @@ -18439,7 +19570,7 @@ soap_send_empty_response(struct soap *soap, int httpstatuscode) soap->omode = (m & ~SOAP_IO) | SOAP_IO_BUFFER; (void)soap_response(soap, httpstatuscode); (void)soap_end_send(soap); /* force end of sends */ - soap->error = SOAP_STOP; /* stops the server (from returning another response */ + soap->error = SOAP_STOP; /* stops the server from returning another response */ soap->omode = m; } return soap_closesock(soap); @@ -18455,30 +19586,18 @@ SOAP_FMAC1 int SOAP_FMAC2 soap_recv_empty_response(struct soap *soap) -{ if (!(soap->omode & SOAP_IO_UDP)) - { if (!soap_begin_recv(soap)) - { if (soap->body) - { if ((soap->status != 400 && soap->status != 500) - || soap_envelope_begin_in(soap) - || soap_recv_header(soap) - || soap_body_begin_in(soap)) - { -#ifndef WITH_LEAN - const char *s = soap_get_http_body(soap, NULL); -#endif - (void)soap_end_recv(soap); +{ soap->error = SOAP_OK; + if (!(soap->omode & SOAP_IO_UDP) && !(soap->omode & SOAP_ENC_PLAIN)) + { if (soap_begin_recv(soap) == SOAP_OK) + { #ifndef WITH_LEAN - if (s) - soap_set_receiver_error(soap, "HTTP Error", s, soap->status); + const char *s = soap_get_http_body(soap, NULL); + if (s) + soap_set_receiver_error(soap, "HTTP Error", s, soap->status); #endif - } - else - return soap_recv_fault(soap, 1); - } - else - (void)soap_end_recv(soap); + (void)soap_end_recv(soap); } - else if (soap->error == SOAP_NO_DATA || soap->error == 200 || soap->error == 202) + else if (soap->error == SOAP_NO_DATA || soap->error == 200 || soap->error == 201 || soap->error == 202) soap->error = SOAP_OK; } return soap_closesock(soap); @@ -18525,14 +19644,18 @@ soap_strerror(struct soap *soap) #endif } else - { int rt = soap->recv_timeout, st = soap->send_timeout; + { int tt = soap->transfer_timeout, rt = soap->recv_timeout, st = soap->send_timeout; #ifndef WITH_LEAN - int ru = ' ', su = ' '; + int tu = ' ', ru = ' ', su = ' '; #endif soap_strcpy(soap->msgbuf, sizeof(soap->msgbuf), "message transfer interrupted"); - if (rt || st) + if (tt | rt || st) soap_strcpy(soap->msgbuf + 28, sizeof(soap->msgbuf) - 28, " or timed out"); #ifndef WITH_LEAN + if (tt < 0) + { tt = -tt; + tu = 'u'; + } if (rt < 0) { rt = -rt; ru = 'u'; @@ -18541,13 +19664,17 @@ soap_strerror(struct soap *soap) { st = -st; su = 'u'; } + if (tt) + { size_t l = strlen(soap->msgbuf); + (SOAP_SNPRINTF(soap->msgbuf + l, sizeof(soap->msgbuf) - l, 43), " (%d%csec max transfer time)", tt, tu); + } if (rt) { size_t l = strlen(soap->msgbuf); - (SOAP_SNPRINTF(soap->msgbuf + l, sizeof(soap->msgbuf) - l, 36), " (%d%cs recv delay)", rt, ru); + (SOAP_SNPRINTF(soap->msgbuf + l, sizeof(soap->msgbuf) - l, 40), " (%d%csec max recv delay)", rt, ru); } if (st) { size_t l = strlen(soap->msgbuf); - (SOAP_SNPRINTF(soap->msgbuf + l, sizeof(soap->msgbuf) - l, 36), " (%d%cs send delay)", st, su); + (SOAP_SNPRINTF(soap->msgbuf + l, sizeof(soap->msgbuf) - l, 40), " (%d%csec max send delay)", st, su); } #endif } @@ -18602,6 +19729,7 @@ soap_set_receiver_error(struct soap *soap, const char *faultstring, const char * static int soap_copy_fault(struct soap *soap, const char *faultcode, const char *faultsubcodeQName, const char *faultstring, const char *faultdetailXML) { char *r = NULL, *s = NULL, *t = NULL; + DBGFUN2("soap_copy_fault", "code=%s", faultcode ? faultcode : "(null)", "string=%s", faultstring ? faultstring : "(null)") if (faultsubcodeQName) r = soap_strdup(soap, faultsubcodeQName); if (faultstring) @@ -18742,9 +19870,15 @@ soap_sprint_fault(struct soap *soap, char *buf, size_t len) } if (soap->version == 2) v = soap_check_faultsubcode(soap); + if (!v) + v = "no subcode"; s = *soap_faultstring(soap); + if (!s) + s = "[no reason]"; d = soap_check_faultdetail(soap); - (SOAP_SNPRINTF(buf, len, strlen(*c) + strlen(v) + strlen(s) + strlen(d) + 72), "%s%d fault %s [%s]\n\"%s\"\nDetail: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, *c, v ? v : "no subcode", s ? s : "[no reason]", d ? d : "[no detail]"); + if (!d) + d = "[no detail]"; + (SOAP_SNPRINTF(buf, len, strlen(*c) + strlen(v) + strlen(s) + strlen(d) + 72), "%s%d fault %s [%s]\n\"%s\"\nDetail: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, *c, v, s, d); } return buf; } @@ -18762,7 +19896,7 @@ soap_print_fault_location(struct soap *soap, FILE *fd) { #ifndef WITH_LEAN int i, j, c1, c2; - if (soap->error && soap->error != SOAP_STOP && soap->bufidx <= soap->buflen && soap->buflen > 0 && soap->buflen <= sizeof(soap->buf)) + if (soap_check_state(soap) == SOAP_OK && soap->error && soap->error != SOAP_STOP && soap->bufidx <= soap->buflen && soap->buflen > 0 && soap->buflen <= sizeof(soap->buf)) { i = (int)soap->bufidx - 1; if (i <= 0) i = 0; @@ -18790,6 +19924,42 @@ soap_print_fault_location(struct soap *soap, FILE *fd) /******************************************************************************/ +#ifdef __cplusplus +#ifndef WITH_LEAN +#ifndef WITH_NOSTDLIB +#ifndef WITH_COMPAT +SOAP_FMAC1 +void +SOAP_FMAC2 +soap_stream_fault_location(struct soap *soap, std::ostream& os) +{ + int i, j, c1, c2; + if (soap_check_state(soap) == SOAP_OK && soap->error && soap->error != SOAP_STOP && soap->bufidx <= soap->buflen && soap->buflen > 0 && soap->buflen <= sizeof(soap->buf)) + { i = (int)soap->bufidx - 1; + if (i <= 0) + i = 0; + c1 = soap->buf[i]; + soap->buf[i] = '\0'; + if ((int)soap->buflen >= i + 1024) + j = i + 1023; + else + j = (int)soap->buflen - 1; + c2 = soap->buf[j]; + soap->buf[j] = '\0'; + os << soap->buf << (char)c1 << std::endl << "<!-- ** HERE ** -->" << std::endl; + if (soap->bufidx < soap->buflen) + os << soap->buf + soap->bufidx << std::endl; + soap->buf[i] = (char)c1; + soap->buf[j] = (char)c2; + } +} +#endif +#endif +#endif +#endif + +/******************************************************************************/ + #ifndef PALM_1 SOAP_FMAC1 int |