source: rtems/testsuites/libtests/mghttpd01/test-http-client.c @ b2ee119f

4.115
Last change on this file since b2ee119f was f42d429, checked in by Nick Withers <nick.withers@…>, on 12/15/14 at 02:26:31

Enable WebSocket? support in the Mongoose HTTP server

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Obere Lagerstr. 30
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15
16#include <sys/types.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <netinet/tcp.h>
20#include <netdb.h>
21#include <limits.h>
22#include <unistd.h>
23#include <stdint.h>
24#include <string.h>
25
26#include <tmacros.h>
27
28#include "test-http-client.h"
29
30#define HTTPC_WS_CONN_REQ  "GET / HTTP/1.1\r\n" \
31                           "Host: localhost\r\n" \
32                           "Upgrade: websocket\r\n" \
33                           "Connection: Upgrade\r\n" \
34                           "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" \
35                           "Sec-WebSocket-Version: 13\r\n" \
36                           "\r\n"
37#define HTTPC_WS_CONN_RESP "HTTP/1.1 101 Switching Protocols\r\n" \
38                           "Upgrade: websocket\r\n" \
39                           "Connection: Upgrade\r\n" \
40                           "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" \
41                           "\r\n"
42
43static ssize_t httpc_read_full(
44  const httpc_context *ctx,
45  void *response,
46  size_t responsesize
47);
48
49void httpc_init_context(
50  httpc_context *ctx
51)
52{
53  ctx->socket = -1;
54  ctx->fd = NULL;
55}
56
57bool httpc_open_connection(
58  httpc_context *ctx,
59  const char *targethost,
60  int targetport
61)
62{
63  struct sockaddr_in addr;
64
65  struct hostent *server;
66
67  ctx->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
68  if(ctx->socket < 0) { return false; }
69
70  memset(&addr, 0, sizeof(addr));
71  addr.sin_family = AF_INET;
72  addr.sin_port = htons(targetport);
73
74  server = gethostbyname(targethost);
75  if(server == NULL) { return false; }
76  memcpy(&addr.sin_addr.s_addr, server->h_addr, (size_t) server->h_length);
77
78  if(connect(ctx->socket, (struct sockaddr *)&addr, sizeof(addr)) != 0)
79  {
80    return false;
81  }
82
83  ctx->fd = fdopen(ctx->socket,"rw");
84  if(ctx->fd == NULL) { return false; }
85
86  return true;
87}
88
89bool httpc_close_connection(
90  httpc_context *ctx
91)
92{
93  if(close(ctx->socket) != 0)
94  {
95    return false;
96  }
97
98  return true;
99}
100
101bool httpc_send_request(
102  const httpc_context *ctx,
103  const char *request,
104  char *response,
105  int responsesize
106)
107{
108  rtems_test_assert(ctx != NULL);
109  rtems_test_assert(ctx->socket >= 0);
110  rtems_test_assert(request != NULL);
111  rtems_test_assert(response != NULL);
112  rtems_test_assert(responsesize > 1);
113
114  static const char * const lineend = " HTTP/1.1\r\n\r\n";
115
116  write(ctx->socket, request, strlen(request));
117  write(ctx->socket, lineend, strlen(lineend));
118
119  ssize_t size;
120  if((size = httpc_read_full(ctx, response, responsesize - 1)) == -1)
121  {
122    return false;
123  }
124  *(response + size) = '\0';
125
126  return true;
127}
128
129bool httpc_ws_open_connection(
130  const httpc_context *ctx
131)
132{
133  rtems_test_assert(ctx != NULL);
134  rtems_test_assert(ctx->socket >= 0);
135
136  write(ctx->socket, HTTPC_WS_CONN_REQ, strlen(HTTPC_WS_CONN_REQ));
137
138  char response[strlen(HTTPC_WS_CONN_RESP)];
139  if(httpc_read_full(ctx, response, sizeof(response)) != sizeof(response))
140  {
141    return false;
142  }
143  if(strncmp(response, HTTPC_WS_CONN_RESP, sizeof(response)) != 0)
144  {
145    return false;
146  }
147
148  return true;
149}
150
151bool httpc_ws_send_request(
152  const httpc_context *ctx,
153  const char *request,
154  char *response,
155  int responsesize
156)
157{
158  rtems_test_assert(ctx != NULL);
159  rtems_test_assert(ctx->socket >= 0);
160  rtems_test_assert(request != NULL);
161  rtems_test_assert(response != NULL);
162  rtems_test_assert(responsesize > 0);
163
164  static const uint16_t ws_header_fin  = 1U << 15;
165  static const uint16_t ws_header_text = 1U << 8;
166  static const uint16_t ws_header_size = 0x7FU;
167
168  /*
169   * We don't support sending WebSocket messages which require multiple
170   * chunks
171   */
172  if(strlen(request) > ws_header_size) { return false; }
173
174  uint16_t header = htons(ws_header_fin | ws_header_text | strlen(request));
175
176  write(ctx->socket, &header, sizeof(header));
177  write(ctx->socket, request, strlen(request));
178
179  if (httpc_read_full(ctx, &header, sizeof(header)) != sizeof(header))
180  {
181    return false;
182  }
183  header = ntohs(header);
184  if (!(header & ws_header_fin)) { return false; }
185  if (!(header & ws_header_text)) { return false; }
186  if (responsesize < (header & ws_header_size) + 1) { return false; }
187
188  responsesize = header & ws_header_size;
189  if (httpc_read_full(ctx, response, responsesize) != responsesize)
190  {
191    return false;
192  }
193  *(response + responsesize) = '\0';
194
195  return true;
196}
197
198
199static ssize_t httpc_read_full(
200  const httpc_context *ctx,
201  void *response,
202  size_t responsesize
203)
204{
205  rtems_test_assert(ctx != NULL);
206  rtems_test_assert(ctx->socket >= 0);
207  rtems_test_assert(response != NULL);
208  rtems_test_assert(responsesize > 0);
209
210  if (responsesize > SSIZE_MAX) { return -1; }
211
212  unsigned char *pos = response;
213
214  while(pos < (unsigned char *)response + responsesize)
215  {
216    ssize_t size =
217      read(ctx->socket, pos, (unsigned char *)response + responsesize - pos);
218    if (size == -1) { return -1; }
219    if (size == 0) { break; }
220    pos += size;
221  }
222
223  return (pos - (unsigned char *)response);
224}
Note: See TracBrowser for help on using the repository browser.