soapd.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Copyright (C) 2012-2013 by egnite GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. #include <pro/soap.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. /* Use for local debugging only. Do NOT include into NUTDEBUG.
  38. #define DEBUG_SOAPD
  39. */
  40. #ifdef DEBUG_SOAPD
  41. #include <stdio.h>
  42. #endif
  43. static int ReadTag(HTTP_STREAM *stream, SOAP_TAG *tag, int avail)
  44. {
  45. int rc;
  46. char *cp;
  47. memset(tag, 0, sizeof(*tag));
  48. avail = avail > SOAP_MAX_TAG_SIZE ? SOAP_MAX_TAG_SIZE : avail;
  49. rc = StreamReadUntilChars(stream, ">", NULL, tag->soap_buff, avail);
  50. if (rc > 0) {
  51. cp = tag->soap_buff;
  52. if (*cp == '/') {
  53. cp++;
  54. tag->soap_ttf = SOAPTYPE_ETAG;
  55. }
  56. tag->soap_name._name = cp;
  57. while (*cp && *cp != ' ') {
  58. if (*cp == ':') {
  59. *cp++ = '\0';
  60. tag->soap_name._namespace = tag->soap_name._name;
  61. tag->soap_name._name = cp;
  62. } else {
  63. cp++;
  64. }
  65. }
  66. if (tag->soap_ttf == 0) {
  67. int ac;
  68. for (ac = 0; *cp && ac < SOAP_MAX_TAG_ATTRIBUTES; ac++) {
  69. *cp = '\0';
  70. while (*++cp == ' ');
  71. if (*cp == '/' && *(cp + 1) == '\0') {
  72. tag->soap_ttf = SOAPTYPE_EOTAG;
  73. break;
  74. }
  75. tag->soap_attr[ac].attr_name._name = cp;
  76. while (*cp && *cp != '=') {
  77. if (*cp == ':') {
  78. *cp++ = '\0';
  79. tag->soap_attr[ac].attr_name._namespace = tag->soap_attr[ac].attr_name._name;
  80. tag->soap_attr[ac].attr_name._name = cp;
  81. } else {
  82. cp++;
  83. }
  84. }
  85. if (*cp) {
  86. uint_fast8_t quoted = *++cp == '"';
  87. cp += quoted;
  88. tag->soap_attr[ac].attr_value = cp;
  89. while (*cp) {
  90. if (quoted) {
  91. if (*cp == '"') {
  92. break;
  93. }
  94. }
  95. else if (*cp == ' ') {
  96. break;
  97. }
  98. cp++;
  99. }
  100. if (*cp) {
  101. *cp++ = '\0';
  102. }
  103. }
  104. }
  105. }
  106. }
  107. return rc;
  108. }
  109. SOAP_PROCEDURE *SoapParseCallRequest(HTTP_STREAM *stream, int avail, SOAP_PROCEDURE *list)
  110. {
  111. SOAP_PROCEDURE *proc = NULL;
  112. SOAP_ARG *arg = NULL;
  113. SOAP_TAG *tag;
  114. int bufsiz;
  115. int got;
  116. int in_body = 0;
  117. tag = malloc(sizeof(*tag));
  118. if (avail < 16 || tag == NULL) {
  119. return NULL;
  120. }
  121. while (avail) {
  122. /* Read all characters up to the next tag, but honor limits. */
  123. bufsiz = avail > SOAP_MAX_TAG_SIZE ? SOAP_MAX_TAG_SIZE : avail;
  124. got = StreamReadUntilChars(stream, "<", NULL, tag->soap_buff, bufsiz);
  125. avail -= got;
  126. if (got <= 0 || avail <= 4) {
  127. break;
  128. }
  129. tag->soap_buff[got] = '\0';
  130. /* If we are inside an argument, then this is the value. */
  131. if (arg) {
  132. free(arg->arg_val);
  133. arg->arg_val = strdup(tag->soap_buff);
  134. }
  135. /* Now read the tag. */
  136. got = ReadTag(stream, tag, avail);
  137. avail -= got;
  138. if (got <= 0) {
  139. break;
  140. }
  141. /* Check for envelope tag. */
  142. if (strcmp(tag->soap_name._name, "Envelope") == 0) {
  143. if (tag->soap_ttf) {
  144. /* Closing tag, update state. */
  145. in_body = 0;
  146. }
  147. }
  148. /* Check for body tag. */
  149. else if (strcmp(tag->soap_name._name, "Body") == 0) {
  150. /* Update state according to opening or closing tags. */
  151. in_body = tag->soap_ttf == 0;
  152. }
  153. /* Check for other tags only if we are inside a body. */
  154. else if (in_body) {
  155. if (proc == NULL) {
  156. /* First tag in a body specifies the action. */
  157. for (proc = list; proc; proc = proc->proc_next) {
  158. if (strcasecmp(tag->soap_name._name, proc->proc_name) == 0) {
  159. break;
  160. }
  161. }
  162. } else {
  163. /* Following tags in a body contain arguments. */
  164. if (tag->soap_ttf == 0) {
  165. /* Opening tag. */
  166. for (arg = proc->proc_argi; arg; arg = arg->arg_next) {
  167. if (strcasecmp(tag->soap_name._name, arg->arg_name) == 0) {
  168. break;
  169. }
  170. }
  171. } else {
  172. arg = NULL;
  173. }
  174. }
  175. }
  176. }
  177. return proc;
  178. }
  179. int SoapSendCallResponse(HTTP_STREAM *stream, SOAP_PROCEDURE *proc, const char *domain, const char *type)
  180. {
  181. SOAP_ARG *arg;
  182. HttpSendStreamHeaderTop(stream, 200);
  183. s_puts("SERVER: NutOS/5.0 UPnP/1.0 TestUPnP/1.0\r\n", stream);
  184. s_puts("EXT:\r\n", stream);
  185. HttpSendStreamHeaderBottom(stream, "text", "xml", HTTP_CONN_CLOSE, -1);
  186. s_puts(
  187. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
  188. "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  189. "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
  190. "<s:Body>\r\n", stream);
  191. s_printf(stream, "<u:%sResponse xmlns:u=\"urn:%s:service:%s:1\">\r\n", proc->proc_name, domain, type);
  192. for (arg = proc->proc_argo; arg; arg = arg->arg_next) {
  193. if (proc->proc_argo->arg_val) {
  194. s_printf(stream, "<%s>%s</%s>\r\n", proc->proc_argo->arg_name, proc->proc_argo->arg_val, proc->proc_argo->arg_name);
  195. }
  196. }
  197. s_printf(stream, "</u:%sResponse>\r\n", proc->proc_name);
  198. s_puts("</s:Body>\r\n"
  199. "</s:Envelope>\r\n", stream);
  200. s_flush(stream);
  201. return 0;
  202. }