http_client.xml 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <class name="HTTPClient">
  2. <relationships>
  3. <association name="parent" class="MvKController" min="1" max="1"/>
  4. </relationships>
  5. <constructor>
  6. <parameter name="hostname"/>
  7. <parameter name="port"/>
  8. <body>
  9. <![CDATA[
  10. self.socket = None
  11. self.destination = (hostname, port)
  12. self.received_data = ""
  13. self.send_data = ""
  14. self.queue = []
  15. self.destinations = []
  16. ]]>
  17. </body>
  18. </constructor>
  19. <scxml initial="init">
  20. <state id="init">
  21. <onentry>
  22. <raise scope="output" event="create_socket" output="socket_out"/>
  23. </onentry>
  24. <transition port="socket_in" event="created_socket" target="../connecting">
  25. <parameter name="socket"/>
  26. <script>
  27. self.socket = socket
  28. </script>
  29. </transition>
  30. </state>
  31. <state id="connecting">
  32. <onentry>
  33. <raise scope="output" event="connect_socket" output="socket_out">
  34. <parameter expr="self.socket"/>
  35. <parameter expr="self.destination"/>
  36. </raise>
  37. </onentry>
  38. <transition port="socket_in" event="connected_socket" cond="self.socket == socket" target="../connected">
  39. <parameter name="socket"/>
  40. <raise scope="broad" event="http_client_ready"/>
  41. <script>
  42. </script>
  43. </transition>
  44. </state>
  45. <parallel id="connected">
  46. <state id="listening" initial="listen">
  47. <state id="listen">
  48. <onentry>
  49. <raise scope="output" port="socket_out" event="recv_socket">
  50. <parameter expr="self.socket"/>
  51. </raise>
  52. </onentry>
  53. <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) > 0)" target=".">
  54. <parameter name="socket"/>
  55. <parameter name="data"/>
  56. <script>
  57. self.received_data += data
  58. </script>
  59. </transition>
  60. <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) == 0)" target="../close">
  61. <parameter name="socket"/>
  62. <parameter name="data"/>
  63. </transition>
  64. </state>
  65. <state id="close">
  66. </state>
  67. </state>
  68. <state id="sending" initial="waiting_for_data">
  69. <state id="waiting_for_data">
  70. <transition cond="len(self.send_data) > 0" target="../transferring">
  71. <raise scope="output" port="socket_out" event="send_socket">
  72. <parameter expr="self.socket"/>
  73. <parameter expr="self.send_data"/>
  74. </raise>
  75. </transition>
  76. </state>
  77. <state id="transferring">
  78. <transition event="sent_socket" port="socket_in" cond="self.socket == socket" target="../waiting_for_data">
  79. <parameter name="socket"/>
  80. <parameter name="sent_bytes"/>
  81. <script>
  82. self.send_data = self.send_data[sent_bytes:]
  83. </script>
  84. </transition>
  85. </state>
  86. </state>
  87. <state id="queueing">
  88. <state id="queueing">
  89. <onentry>
  90. </onentry>
  91. <transition event="HTTP_input" target=".">
  92. <parameter name="data"/>
  93. <parameter name="destination"/>
  94. <script>
  95. self.send_data += "POST / HTTP/1.0\r\n"
  96. self.send_data += "Content-Length: %i\r\n" % len(str(data))
  97. self.send_data += "\r\n"
  98. self.send_data += data
  99. self.destinations.append(destination)
  100. </script>
  101. </transition>
  102. </state>
  103. </state>
  104. <state id="parsing" initial="wait_for_header">
  105. <state id="wait_for_header">
  106. <transition cond="'\r\n\r\n' in self.received_data" target="../wait_for_payload">
  107. <script>
  108. header, self.received_data = self.received_data.split("\r\n\r\n", 1)
  109. header = header.lower()
  110. if "content-length" in header:
  111. _, after = header.split("content-length:", 1)
  112. after, _ = after.split("\r\n", 1)
  113. after = after.strip()
  114. self.length = int(after)
  115. else:
  116. self.length = float('inf')
  117. </script>
  118. </transition>
  119. </state>
  120. <state id="wait_for_payload">
  121. <transition cond="len(self.received_data) >= self.length" target="../wait_for_header">
  122. <script>
  123. data = self.received_data[:self.length]
  124. self.received_data = self.received_data[self.length:]
  125. params = dict([p.split('=') for p in data.split('&amp;')])
  126. data = {k: urllib.unquote_plus(v) for k, v in params.iteritems()}
  127. </script>
  128. <raise event="HTTP_output" scope="narrow" target="self.destinations.pop(0)">
  129. <parameter expr="data"/>
  130. </raise>
  131. </transition>
  132. </state>
  133. </state>
  134. </parallel>
  135. </scxml>
  136. </class>