Coverage Report

Created: 2026-07-25 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libsoup/libsoup/http1/soup-message-io-data.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
/*
3
 * soup-message-io-data.c: HTTP message I/O data
4
 *
5
 * Copyright (C) 2000-2003, Ximian, Inc.
6
 */
7
8
#ifdef HAVE_CONFIG_H
9
#include "config.h"
10
#endif
11
12
#include <glib/gi18n-lib.h>
13
14
#include "soup-message-io-data.h"
15
#include "soup-message-private.h"
16
#include "soup-server-message-private.h"
17
#include "soup.h"
18
19
0
#define RESPONSE_BLOCK_SIZE 8192
20
0
#define HEADER_SIZE_LIMIT (100 * 1024)
21
22
void
23
soup_message_io_data_cleanup (SoupMessageIOData *io)
24
0
{
25
0
  if (io->io_source) {
26
0
    g_source_destroy (io->io_source);
27
0
    g_clear_pointer (&io->io_source, g_source_unref);
28
0
  }
29
30
0
  if (io->body_istream)
31
0
    g_object_unref (io->body_istream);
32
0
  if (io->body_ostream)
33
0
    g_object_unref (io->body_ostream);
34
35
0
  g_byte_array_free (io->read_header_buf, TRUE);
36
37
0
  g_string_free (io->write_buf, TRUE);
38
39
0
  if (io->async_wait) {
40
0
    g_cancellable_cancel (io->async_wait);
41
0
    g_clear_object (&io->async_wait);
42
0
  }
43
0
  g_clear_error (&io->async_error);
44
0
}
45
46
gboolean
47
soup_message_io_data_read_headers (SoupMessageIOData     *io,
48
                                   SoupFilterInputStream *istream,
49
                                   gboolean               blocking,
50
                                   GCancellable          *cancellable,
51
                                   gushort               *extra_bytes,
52
                                   GError               **error)
53
0
{
54
0
  gssize nread, old_len;
55
0
  gboolean got_lf;
56
57
0
  while (1) {
58
0
    old_len = io->read_header_buf->len;
59
0
    g_byte_array_set_size (io->read_header_buf, old_len + RESPONSE_BLOCK_SIZE);
60
0
    nread = soup_filter_input_stream_read_line (istream,
61
0
                  io->read_header_buf->data + old_len,
62
0
                  RESPONSE_BLOCK_SIZE,
63
0
                  blocking,
64
0
                  &got_lf,
65
0
                  cancellable, error);
66
0
    io->read_header_buf->len = old_len + MAX (nread, 0);
67
0
    if (nread == 0) {
68
0
      if (io->read_header_buf->len > 0) {
69
0
                                if (extra_bytes)
70
0
          *extra_bytes = 0;
71
0
        break;
72
0
                        }
73
74
0
      g_set_error_literal (error, G_IO_ERROR,
75
0
               G_IO_ERROR_PARTIAL_INPUT,
76
0
               _("Connection terminated unexpectedly"));
77
0
    }
78
0
    if (nread <= 0)
79
0
      return FALSE;
80
81
0
    if (got_lf) {
82
0
      if (nread == 1 && old_len >= 2 &&
83
0
          !strncmp ((char *)io->read_header_buf->data +
84
0
              io->read_header_buf->len - 2,
85
0
              "\n\n", 2)) {
86
0
        io->read_header_buf->len--;
87
0
                                if (extra_bytes)
88
0
                                        *extra_bytes = 1;
89
0
        break;
90
0
      } else if (nread == 2 && old_len >= 3 &&
91
0
         !strncmp ((char *)io->read_header_buf->data +
92
0
             io->read_header_buf->len - 3,
93
0
             "\n\r\n", 3)) {
94
0
        io->read_header_buf->len -= 2;
95
0
                                if (extra_bytes)
96
0
                                        *extra_bytes = 2;
97
0
        break;
98
0
      }
99
0
    }
100
101
0
    if (io->read_header_buf->len > HEADER_SIZE_LIMIT) {
102
0
      g_set_error_literal (error, G_IO_ERROR,
103
0
               G_IO_ERROR_PARTIAL_INPUT,
104
0
               _("Header too big"));
105
0
      return FALSE;
106
0
    }
107
0
  }
108
109
0
  io->read_header_buf->data[io->read_header_buf->len] = '\0';
110
0
  return TRUE;
111
0
}
112
113
static gboolean
114
message_io_is_paused (GObject *msg)
115
0
{
116
0
  if (SOUP_IS_MESSAGE (msg))
117
0
    return soup_message_is_io_paused (SOUP_MESSAGE (msg));
118
119
0
  if (SOUP_IS_SERVER_MESSAGE (msg))
120
0
    return soup_server_message_is_io_paused (SOUP_SERVER_MESSAGE (msg));
121
122
0
  return FALSE;
123
0
}
124
125
static gboolean
126
message_io_source_check (GSource *source)
127
0
{
128
0
  SoupMessageIOSource *message_source = (SoupMessageIOSource *)source;
129
130
0
  if (message_source->paused) {
131
0
    if (message_io_is_paused (message_source->msg))
132
0
      return FALSE;
133
0
    return TRUE;
134
0
  } else
135
0
    return FALSE;
136
0
}
137
138
GSource *
139
soup_message_io_data_get_source (SoupMessageIOData      *io,
140
         GObject                *msg,
141
                                 GInputStream           *istream,
142
                                 GOutputStream          *ostream,
143
         GCancellable           *cancellable,
144
         SoupMessageIOSourceFunc callback,
145
         gpointer                user_data)
146
0
{
147
0
  GSource *base_source, *source;
148
149
0
  if (!io) {
150
0
    base_source = g_timeout_source_new (0);
151
0
  } else if (io->paused) {
152
0
    base_source = cancellable ? g_cancellable_source_new (cancellable) : NULL;
153
0
  } else if (io->async_wait) {
154
0
    base_source = g_cancellable_source_new (io->async_wait);
155
0
  } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) {
156
0
    GPollableInputStream *stream;
157
158
0
    if (io->body_istream)
159
0
      stream = G_POLLABLE_INPUT_STREAM (io->body_istream);
160
0
                else if (istream)
161
0
                        stream = G_POLLABLE_INPUT_STREAM (istream);
162
0
                else
163
0
                        g_assert_not_reached ();
164
0
    base_source = g_pollable_input_stream_create_source (stream, cancellable);
165
0
  } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) {
166
0
    GPollableOutputStream *stream;
167
168
0
    if (io->body_ostream)
169
0
      stream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream);
170
0
                else if (ostream)
171
0
                        stream = G_POLLABLE_OUTPUT_STREAM (ostream);
172
0
                else
173
0
                        g_assert_not_reached ();
174
0
    base_source = g_pollable_output_stream_create_source (stream, cancellable);
175
0
  } else
176
0
    base_source = g_timeout_source_new (0);
177
178
0
        source = soup_message_io_source_new (base_source, msg, io && io->paused, message_io_source_check);
179
0
  g_source_set_static_name (source, "SoupMessageIOData");
180
0
  g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL);
181
0
  return source;
182
0
}
183
184
void
185
soup_message_io_data_pause (SoupMessageIOData *io)
186
0
{
187
0
  if (io->io_source) {
188
0
    g_source_destroy (io->io_source);
189
0
    g_clear_pointer (&io->io_source, g_source_unref);
190
0
  }
191
192
0
  io->paused = TRUE;
193
0
}
194
195
void
196
soup_message_io_data_unpause (SoupMessageIOData *io)
197
0
{
198
0
        io->paused = FALSE;
199
0
}