Coverage Report

Created: 2025-12-16 08:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/secure-streams/system/fetch-policy/fetch-policy.c
Line
Count
Source
1
/*
2
 * Policy fetching for Secure Streams
3
 *
4
 * libwebsockets - small server side websockets and web server implementation
5
 *
6
 * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to
10
 * deal in the Software without restriction, including without limitation the
11
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
 * sell copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
 * IN THE SOFTWARE.
25
 */
26
27
#include <private-lib-core.h>
28
29
typedef struct ss_fetch_policy {
30
  struct lws_ss_handle  *ss;
31
  void      *opaque_data;
32
  /* ... application specific state ... */
33
34
  lws_sorted_usec_list_t  sul;
35
36
  uint8_t     partway;
37
} ss_fetch_policy_t;
38
39
/* secure streams payload interface */
40
41
static lws_ss_state_return_t
42
ss_fetch_policy_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
43
0
{
44
0
  ss_fetch_policy_t *m = (ss_fetch_policy_t *)userobj;
45
0
  struct lws_context *context = (struct lws_context *)m->opaque_data;
46
47
0
  if (flags & LWSSS_FLAG_SOM) {
48
0
    if (lws_ss_policy_parse_begin(context, 0))
49
0
      return LWSSSSRET_OK;
50
0
    m->partway = 1;
51
0
  }
52
53
0
  if (len && lws_ss_policy_parse(context, buf, len) < 0)
54
0
    return LWSSSSRET_OK;
55
56
0
  if (flags & LWSSS_FLAG_EOM)
57
0
    m->partway = 2;
58
59
0
  return LWSSSSRET_OK;
60
0
}
61
62
static lws_ss_state_return_t
63
ss_fetch_policy_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
64
       size_t *len, int *flags)
65
0
{
66
0
  return LWSSSSRET_TX_DONT_SEND;
67
0
}
68
69
static void
70
policy_set(lws_sorted_usec_list_t *sul)
71
0
{
72
0
  ss_fetch_policy_t *m = lws_container_of(sul, ss_fetch_policy_t, sul);
73
0
  struct lws_context *context = (struct lws_context *)m->opaque_data;
74
75
  /*
76
   * We get called if the policy parse was successful, just after the
77
   * ss connection close that was using the vhost from the old policy
78
   */
79
80
0
  lws_ss_destroy(&m->ss);
81
82
0
  if (lws_ss_policy_set(context, "updated"))
83
0
    lwsl_err("%s: policy set failed\n", __func__);
84
0
  else {
85
0
    context->policy_updated = 1;
86
0
#if defined(LWS_WITH_SYS_STATE)
87
0
    lws_state_transition_steps(&context->mgr_system,
88
0
             LWS_SYSTATE_OPERATIONAL);
89
0
#endif
90
0
  }
91
0
}
92
93
static lws_ss_state_return_t
94
ss_fetch_policy_state(void *userobj, void *sh, lws_ss_constate_t state,
95
          lws_ss_tx_ordinal_t ack)
96
0
{
97
0
  ss_fetch_policy_t *m = (ss_fetch_policy_t *)userobj;
98
0
  struct lws_context *context = (struct lws_context *)m->opaque_data;
99
100
0
  lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
101
0
      (unsigned int)ack);
102
103
0
  switch (state) {
104
0
  case LWSSSCS_CREATING:
105
0
    return lws_ss_request_tx(m->ss);
106
107
0
  case LWSSSCS_CONNECTING:
108
0
    break;
109
110
0
  case LWSSSCS_QOS_ACK_REMOTE:
111
0
    switch (m->partway) {
112
0
    case 2:
113
0
      lws_sul_schedule(context, 0, &m->sul, policy_set, 1);
114
0
      m->partway = 0;
115
0
      break;
116
0
    }
117
0
    break;
118
119
0
  case LWSSSCS_DISCONNECTED:
120
0
    if (m->partway == 1) {
121
0
      lws_ss_policy_parse_abandon(context);
122
0
      break;
123
0
    }
124
0
    m->partway = 0;
125
0
    break;
126
127
0
  default:
128
0
    break;
129
0
  }
130
131
0
  return LWSSSSRET_OK;
132
0
}
133
134
int
135
lws_ss_sys_fetch_policy(struct lws_context *context)
136
0
{
137
0
  lws_ss_info_t ssi;
138
139
0
  if (context->hss_fetch_policy) /* already exists */
140
0
    return 0;
141
142
  /* We're making an outgoing secure stream ourselves */
143
144
0
  memset(&ssi, 0, sizeof(ssi));
145
0
  ssi.handle_offset     = offsetof(ss_fetch_policy_t, ss);
146
0
  ssi.opaque_user_data_offset = offsetof(ss_fetch_policy_t, opaque_data);
147
0
  ssi.rx          = ss_fetch_policy_rx;
148
0
  ssi.tx          = ss_fetch_policy_tx;
149
0
  ssi.state       = ss_fetch_policy_state;
150
0
  ssi.user_alloc        = sizeof(ss_fetch_policy_t);
151
0
  ssi.streamtype        = "fetch_policy";
152
153
0
  if (lws_ss_create(context, 0, &ssi, context, &context->hss_fetch_policy,
154
0
        NULL, NULL)) {
155
    /*
156
     * If there's no fetch_policy streamtype, it can just be we're
157
     * running on a proxied client with no policy of its own,
158
     * it's OK.
159
     */
160
0
    lwsl_info("%s: Policy fetch ss failed (stub policy?)\n", __func__);
161
162
0
    return 0;
163
0
  }
164
165
0
  lwsl_info("%s: policy fetching ongoing\n", __func__);
166
167
  /* fetching it is ongoing */
168
169
0
  return 1;
170
0
}