• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geographika / mapserver / 12203665581

06 Dec 2024 05:55PM UTC coverage: 40.364% (-0.004%) from 40.368%
12203665581

push

github

geographika
Lint fix

1 of 1 new or added line in 1 file covered. (100.0%)

6 existing lines in 1 file now uncovered.

58376 of 144624 relevant lines covered (40.36%)

25475.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.72
/src/mapio.c
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Implementations for MapServer IO redirection capability.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies of this Software or works derived from this Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 * DEALINGS IN THE SOFTWARE.
28
 ****************************************************************************/
29

30
#include <stdarg.h>
31

32
#include "mapserver.h"
33
#include "mapthread.h"
34

35
#ifdef _WIN32
36
#include <fcntl.h>
37
#include <io.h>
38
#endif
39

40
#ifdef MOD_WMS_ENABLED
41
#include "httpd.h"
42
#include "apr_strings.h"
43
#endif
44

45
static int is_msIO_initialized = MS_FALSE;
46
static int is_msIO_header_enabled = MS_TRUE;
47

48
typedef struct msIOContextGroup_t {
49
  msIOContext stdin_context;
50
  msIOContext stdout_context;
51
  msIOContext stderr_context;
52

53
  void *thread_id;
54
  struct msIOContextGroup_t *next;
55
} msIOContextGroup;
56

57
static msIOContextGroup default_contexts;
58
static msIOContextGroup *io_context_list = NULL;
59
static void msIO_Initialize(void);
60

61
#ifdef msIO_printf
62
#undef msIO_printf
63
#undef msIO_fprintf
64
#undef msIO_fwrite
65
#undef msIO_fread
66
#undef msIO_vfprintf
67
#endif
68

69
/************************************************************************/
70
/*                            msIO_Cleanup()                            */
71
/************************************************************************/
72

73
void msIO_Cleanup()
2,546✔
74

75
{
76
  if (is_msIO_initialized)
2,546✔
77

78
  {
79
    is_msIO_initialized = MS_FALSE;
2,504✔
80
    while (io_context_list != NULL) {
5,010✔
81
      msIOContextGroup *last = io_context_list;
82
      io_context_list = io_context_list->next;
2,506✔
83
      free(last);
2,506✔
84
    }
85
  }
86
}
2,546✔
87

88
/************************************************************************/
89
/*                        msIO_GetContextGroup()                        */
90
/************************************************************************/
91

92
static msIOContextGroup *msIO_GetContextGroup()
2,674✔
93

94
{
95
  void *nThreadId = msGetThreadId();
2,674✔
96
  msIOContextGroup *prev = NULL, *group = io_context_list;
2,674✔
97

98
  if (group != NULL && group->thread_id == nThreadId)
2,674✔
99
    return group;
100

101
  /* -------------------------------------------------------------------- */
102
  /*      Search for group for this thread                                */
103
  /* -------------------------------------------------------------------- */
104
  msAcquireLock(TLOCK_IOCONTEXT);
2,512✔
105
  msIO_Initialize();
2,512✔
106

107
  group = io_context_list;
2,512✔
108
  while (group != NULL && group->thread_id != nThreadId) {
2,515✔
109
    prev = group;
110
    group = group->next;
3✔
111
  }
112

113
  /* -------------------------------------------------------------------- */
114
  /*      If we found it, make sure it is pushed to the front of the      */
115
  /*      link for faster finding next time, and return it.               */
116
  /* -------------------------------------------------------------------- */
117
  if (group != NULL) {
2,512✔
UNCOV
118
    if (prev != NULL) {
×
UNCOV
119
      prev->next = group->next;
×
UNCOV
120
      group->next = io_context_list;
×
UNCOV
121
      io_context_list = group;
×
122
    }
123

UNCOV
124
    msReleaseLock(TLOCK_IOCONTEXT);
×
UNCOV
125
    return group;
×
126
  }
127

128
  /* -------------------------------------------------------------------- */
129
  /*      Create a new context group for this thread.                     */
130
  /* -------------------------------------------------------------------- */
131
  group = (msIOContextGroup *)calloc(1, sizeof(msIOContextGroup));
2,512✔
132

133
  group->stdin_context = default_contexts.stdin_context;
2,512✔
134
  group->stdout_context = default_contexts.stdout_context;
2,512✔
135
  group->stderr_context = default_contexts.stderr_context;
2,512✔
136
  group->thread_id = nThreadId;
2,512✔
137

138
  group->next = io_context_list;
2,512✔
139
  io_context_list = group;
2,512✔
140

141
  msReleaseLock(TLOCK_IOCONTEXT);
2,512✔
142

143
  return group;
2,512✔
144
}
145

146
/* returns MS_TRUE if the msIO standard output hasn't been redirected */
147
int msIO_isStdContext() {
5✔
148
  msIOContextGroup *group = io_context_list;
5✔
149
  void *nThreadId = msGetThreadId();
5✔
150
  if (!group || group->thread_id != nThreadId) {
5✔
151
    group = msIO_GetContextGroup();
×
152
    if (!group) {
×
153
      return MS_FALSE; /* probably a bug */
154
    }
155
  }
156
  if (group->stderr_context.cbData == (void *)stderr &&
5✔
157
      group->stdin_context.cbData == (void *)stdin &&
×
158
      group->stdout_context.cbData == (void *)stdout)
×
159
    return MS_TRUE;
×
160
  return MS_FALSE;
161
}
162

163
/************************************************************************/
164
/*                          msIO_getHandler()                           */
165
/************************************************************************/
166

167
msIOContext *msIO_getHandler(FILE *fp)
208,767✔
168

169
{
170
  void *nThreadId = msGetThreadId();
208,767✔
171
  msIOContextGroup *group = io_context_list;
208,767✔
172

173
  msIO_Initialize();
208,767✔
174

175
  if (group == NULL || group->thread_id != nThreadId) {
208,767✔
176
    group = msIO_GetContextGroup();
556✔
177
    if (group == NULL)
556✔
178
      return NULL;
179
  }
180

181
  if (fp == stdin || fp == NULL || strcmp((const char *)fp, "stdin") == 0)
208,767✔
182
    return &(group->stdin_context);
159✔
183
  else if (fp == stdout || strcmp((const char *)fp, "stdout") == 0)
208,608✔
184
    return &(group->stdout_context);
193,687✔
185
  else if (fp == stderr || strcmp((const char *)fp, "stderr") == 0)
14,921✔
186
    return &(group->stderr_context);
×
187
  else
188
    return NULL;
189
}
190

191
/************************************************************************/
192
/*                      msIO_setHeaderEnabled()                         */
193
/************************************************************************/
194

195
void msIO_setHeaderEnabled(int bFlag) { is_msIO_header_enabled = bFlag; }
×
196

197
/************************************************************************/
198
/*                           msIO_setHeader()                           */
199
/************************************************************************/
200

201
void msIO_setHeader(const char *header, const char *value, ...) {
2,636✔
202
  va_list args;
203
  va_start(args, value);
2,636✔
204
#ifdef MOD_WMS_ENABLED
205
  msIOContext *ioctx = msIO_getHandler(stdout);
206
  if (ioctx && !strcmp(ioctx->label, "apache")) {
207

208
    request_rec *r = (request_rec *)(ioctx->cbData);
209
    char *fullvalue = apr_pvsprintf(r->pool, value, args);
210
    if (strcasecmp(header, "Content-Type") == 0) {
211
      r->content_type = fullvalue;
212
    } else if (strcasecmp(header, "Status") == 0) {
213
      r->status = atoi(fullvalue);
214
    } else {
215
      apr_table_setn(r->headers_out, apr_pstrdup(r->pool, header), fullvalue);
216
    }
217
  } else {
218
#endif // MOD_WMS_ENABLED
219
    if (is_msIO_header_enabled) {
2,636✔
220
      msIO_fprintf(stdout, "%s: ", header);
2,636✔
221
      msIO_vfprintf(stdout, value, args);
2,636✔
222
      msIO_fprintf(stdout, "\r\n");
2,636✔
223
    }
224
#ifdef MOD_WMS_ENABLED
225
  }
226
#endif
227
  va_end(args);
2,636✔
228
}
2,636✔
229

230
void msIO_sendHeaders() {
1,958✔
231
#ifdef MOD_WMS_ENABLED
232
  msIOContext *ioctx = msIO_getHandler(stdout);
233
  if (ioctx && !strcmp(ioctx->label, "apache"))
234
    return;
235
#endif // !MOD_WMS_ENABLED
236
  if (is_msIO_header_enabled) {
1,958✔
237
    msIO_printf("\r\n");
1,958✔
238
    fflush(stdout);
1,958✔
239
  }
240
}
1,958✔
241

242
/************************************************************************/
243
/*                        msIO_installHandlers()                        */
244
/************************************************************************/
245

246
int msIO_installHandlers(msIOContext *stdin_context,
2,024✔
247
                         msIOContext *stdout_context,
248
                         msIOContext *stderr_context)
249

250
{
251
  msIOContextGroup *group;
252

253
  msIO_Initialize();
2,024✔
254

255
  group = msIO_GetContextGroup();
2,024✔
256

257
  if (stdin_context == NULL)
2,024✔
258
    group->stdin_context = default_contexts.stdin_context;
6✔
259
  else if (stdin_context != &group->stdin_context)
2,018✔
260
    group->stdin_context = *stdin_context;
1,954✔
261

262
  if (stdout_context == NULL)
2,024✔
263
    group->stdout_context = default_contexts.stdout_context;
3✔
264
  else if (stdout_context != &group->stdout_context)
2,021✔
265
    group->stdout_context = *stdout_context;
2,021✔
266

267
  if (stderr_context == NULL)
2,024✔
268
    group->stderr_context = default_contexts.stderr_context;
6✔
269
  else if (stderr_context != &group->stderr_context)
2,018✔
270
    group->stderr_context = *stderr_context;
1,954✔
271

272
  return MS_TRUE;
2,024✔
273
}
274

275
/************************************************************************/
276
/*                          msIO_contextRead()                          */
277
/************************************************************************/
278

279
int msIO_contextRead(msIOContext *context, void *data, int byteCount)
159✔
280

281
{
282
  if (context->write_channel == MS_TRUE)
159✔
283
    return 0;
284
  else
285
    return context->readWriteFunc(context->cbData, data, byteCount);
159✔
286
}
287

288
/************************************************************************/
289
/*                         msIO_contextWrite()                          */
290
/************************************************************************/
291

292
int msIO_contextWrite(msIOContext *context, const void *data, int byteCount)
193,840✔
293

294
{
295
  if (context->write_channel == MS_FALSE)
193,840✔
296
    return 0;
297
  else
298
    return context->readWriteFunc(context->cbData, (void *)data, byteCount);
193,840✔
299
}
300

301
/* ==================================================================== */
302
/* ==================================================================== */
303
/*      Stdio-like cover functions.                                     */
304
/* ==================================================================== */
305
/* ==================================================================== */
306

307
/************************************************************************/
308
/*                            _ms_vsprintf()                            */
309
/************************************************************************/
310

311
static int _ms_vsprintf(char **workBufPtr, const char *format, va_list ap)
16✔
312

313
{
314
  int ret_val;
315
  int workBufSize = 16000;
316

317
  *workBufPtr = (char *)malloc(workBufSize * sizeof(char));
16✔
318
  if (*workBufPtr == NULL) {
16✔
319
    msSetError(MS_MEMERR, NULL, "_ms_vsprintf()");
×
320
    return -1;
×
321
  }
322

323
#if defined(HAVE_VSNPRINTF)
324
  /* This should grow a big enough buffer to hold any formatted result. */
325
  {
326
    va_list wrk_args;
327

328
#ifdef va_copy
329
    va_copy(wrk_args, ap);
16✔
330
#else
331
    wrk_args = ap;
332
#endif
333

334
    while ((ret_val = vsnprintf(*workBufPtr, workBufSize, format, wrk_args)) >=
20✔
335
               workBufSize - 1 ||
20✔
336
           ret_val == -1) {
337
      workBufSize *= 4;
4✔
338
      *workBufPtr = (char *)realloc(*workBufPtr, workBufSize);
4✔
339
      if (*workBufPtr == NULL) {
4✔
340
        msSetError(MS_MEMERR, NULL, "_ms_vsprintf()");
×
341
        va_end(wrk_args);
×
342
        return -1;
×
343
      }
344
#ifdef va_copy
345
      va_end(wrk_args);
4✔
346
      va_copy(wrk_args, ap);
4✔
347
#else
348
      wrk_args = ap;
349
#endif
350
    }
351
    va_end(wrk_args);
16✔
352
  }
353
#else
354
  /* We do not have vsnprintf()... there is a risk of buffer overrun */
355
  ret_val = vsprintf(*workBufPtr, format, ap);
356

357
  if (ret_val < 0 || ret_val >= workBufSize) {
358
    msSetError(MS_MISCERR, "Possible buffer overrun.", "_ms_vsprintf()");
359
    msFree(*workBufPtr);
360
    *workBufPtr = NULL;
361
    return -1;
362
  }
363
#endif
364

365
  return ret_val;
16✔
366
}
367

368
/************************************************************************/
369
/*                            msIO_printf()                             */
370
/************************************************************************/
371

372
int msIO_printf(const char *format, ...)
18,508✔
373

374
{
375
  va_list args;
376
  int ret;
377
  va_start(args, format);
18,508✔
378
  ret = msIO_vfprintf(stdout, format, args);
18,508✔
379
  va_end(args);
18,508✔
380
  return ret;
18,508✔
381
}
382

383
/************************************************************************/
384
/*                            msIO_fprintf()                            */
385
/************************************************************************/
386

387
int msIO_fprintf(FILE *fp, const char *format, ...)
163,279✔
388

389
{
390
  va_list args;
391
  int ret;
392
  va_start(args, format);
163,279✔
393
  ret = msIO_vfprintf(fp, format, args);
163,279✔
394
  va_end(args);
163,279✔
395
  return ret;
163,279✔
396
}
397

398
/************************************************************************/
399
/*                            msIO_vfprintf()                           */
400
/************************************************************************/
401

402
int msIO_vfprintf(FILE *fp, const char *format, va_list ap)
184,423✔
403

404
{
405
  int return_val;
406
  msIOContext *context;
407
  char workBuf[8000];
408

409
#if !defined(HAVE_VSNPRINTF)
410
  return_val = vsprintf(workBuf, format, ap);
411

412
  if (return_val < 0 || return_val >= sizeof(workBuf)) {
413
    msSetError(MS_MISCERR, "Possible buffer overrun.", "msIO_vfprintf()");
414
    return -1;
415
  }
416

417
  char *outbuf = workBuf;
418

419
#else
420

421
  va_list args_copy;
422
#ifdef va_copy
423
  va_copy(args_copy, ap);
184,423✔
424
#else
425
  args_copy = ap;
426
#endif /* va_copy */
427

428
  char *largerBuf = NULL;
184,423✔
429
  return_val = vsnprintf(workBuf, sizeof(workBuf), format, ap);
430
  if (return_val == -1 || return_val >= (int)sizeof(workBuf) - 1) {
184,423✔
431
    return_val = _ms_vsprintf(&largerBuf, format, args_copy);
16✔
432
  }
433
  va_end(args_copy);
184,423✔
434

435
  if (return_val < 0)
184,423✔
436
    return -1;
437

438
  char *outbuf = largerBuf ? largerBuf : workBuf;
184,423✔
439

440
#endif /* HAVE_VSNPRINTF */
441

442
  context = msIO_getHandler(fp);
184,423✔
443
  if (context == NULL)
184,423✔
444
    return_val = fwrite(outbuf, 1, return_val, fp);
3,163✔
445
  else
446
    return_val = msIO_contextWrite(context, outbuf, return_val);
181,260✔
447

448
#if defined(HAVE_VSNPRINTF)
449
  msFree(largerBuf);
184,423✔
450
#endif
451

452
  return return_val;
184,423✔
453
}
454

455
/************************************************************************/
456
/*                            msIO_fwrite()                             */
457
/************************************************************************/
458

459
int msIO_fwrite(const void *data, size_t size, size_t nmemb, FILE *fp)
23,978✔
460

461
{
462
  msIOContext *context;
463

464
  if (size == 0 || nmemb == 0)
23,978✔
465
    return 0;
466

467
  context = msIO_getHandler(fp);
23,978✔
468
  if (context == NULL)
23,978✔
469
    return fwrite(data, size, nmemb, fp);
11,758✔
470
  else
471
    return msIO_contextWrite(context, data, size * nmemb) / size;
12,220✔
472
}
473

474
/************************************************************************/
475
/*                            msIO_fread()                              */
476
/************************************************************************/
477

478
int msIO_fread(void *data, size_t size, size_t nmemb, FILE *fp)
159✔
479

480
{
481
  msIOContext *context;
482

483
  if (size == 0 || nmemb == 0)
159✔
484
    return 0;
485

486
  context = msIO_getHandler(fp);
159✔
487
  if (context == NULL)
159✔
488
    return fread(data, size, nmemb, fp);
×
489
  else
490
    return msIO_contextRead(context, data, size * nmemb) / size;
159✔
491
}
492

493
/* ==================================================================== */
494
/* ==================================================================== */
495
/*      Internal default callbacks implementing stdio reading and       */
496
/*      writing.                                                        */
497
/* ==================================================================== */
498
/* ==================================================================== */
499

500
/************************************************************************/
501
/*                           msIO_stdioRead()                           */
502
/*                                                                      */
503
/*      This is the default implementation via stdio.                   */
504
/************************************************************************/
505

506
static int msIO_stdioRead(void *cbData, void *data, int byteCount)
×
507

508
{
509
  return fread(data, 1, byteCount, (FILE *)cbData);
×
510
}
511

512
/************************************************************************/
513
/*                          msIO_stdioWrite()                           */
514
/*                                                                      */
515
/*      This is the default implementation via stdio.                   */
516
/************************************************************************/
517

518
static int msIO_stdioWrite(void *cbData, void *data, int byteCount)
×
519

520
{
521
  return fwrite(data, 1, byteCount, (FILE *)cbData);
×
522
}
523

524
/************************************************************************/
525
/*                          msIO_Initialize()                           */
526
/************************************************************************/
527

528
static void msIO_Initialize(void)
213,303✔
529

530
{
531
  if (is_msIO_initialized == MS_TRUE)
213,303✔
532
    return;
533

534
  default_contexts.stdin_context.label = "stdio";
2,510✔
535
  default_contexts.stdin_context.write_channel = MS_FALSE;
2,510✔
536
  default_contexts.stdin_context.readWriteFunc = msIO_stdioRead;
2,510✔
537
  default_contexts.stdin_context.cbData = (void *)stdin;
2,510✔
538

539
  default_contexts.stdout_context.label = "stdio";
2,510✔
540
  default_contexts.stdout_context.write_channel = MS_TRUE;
2,510✔
541
  default_contexts.stdout_context.readWriteFunc = msIO_stdioWrite;
2,510✔
542
  default_contexts.stdout_context.cbData = (void *)stdout;
2,510✔
543

544
  default_contexts.stderr_context.label = "stdio";
2,510✔
545
  default_contexts.stderr_context.write_channel = MS_TRUE;
2,510✔
546
  default_contexts.stderr_context.readWriteFunc = msIO_stdioWrite;
2,510✔
547
  default_contexts.stderr_context.cbData = (void *)stderr;
2,510✔
548

549
  default_contexts.next = NULL;
2,510✔
550
  default_contexts.thread_id = 0;
2,510✔
551

552
  is_msIO_initialized = MS_TRUE;
2,510✔
553
}
554

555
/* ==================================================================== */
556
/* ==================================================================== */
557
/*      FastCGI output redirection functions.                           */
558
/* ==================================================================== */
559
/* ==================================================================== */
560

561
/************************************************************************/
562
/*                       msIO_needBinaryStdout()                        */
563
/*                                                                      */
564
/*      This function is intended to ensure that stdout is in binary    */
565
/*      mode.                                                           */
566
/*                                                                      */
567
/*      But don't do it we are using FastCGI.  We will take care of     */
568
/*      doing it in the libfcgi library in that case for the normal     */
569
/*      cgi case, and for the fastcgi case the _setmode() call          */
570
/*      causes a crash.                                                 */
571
/************************************************************************/
572

573
int msIO_needBinaryStdout()
814✔
574

575
{
576
#if defined(_WIN32) && !defined(USE_FASTCGI)
577
  if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
578
    msSetError(MS_IOERR, "Unable to change stdout to binary mode.",
579
               "msIO_needBinaryStdout()");
580
    return (MS_FAILURE);
581
  }
582
#endif
583

584
  return MS_SUCCESS;
814✔
585
}
586

587
/************************************************************************/
588
/*                        msIO_needBinaryStdin()                        */
589
/*                                                                      */
590
/*      This function is intended to ensure that stdin is in binary     */
591
/*      mode.                                                           */
592
/*                                                                      */
593
/*      But don't do it we are using FastCGI.  We will take care of     */
594
/*      doing it in the libfcgi library in that case for the normal     */
595
/*      cgi case, and for the fastcgi case the _setmode() call          */
596
/*      causes a crash.                                                 */
597
/************************************************************************/
598

599
int msIO_needBinaryStdin()
159✔
600

601
{
602
#if defined(_WIN32) && !defined(USE_FASTCGI)
603
  if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
604
    msSetError(MS_IOERR, "Unable to change stdin to binary mode.",
605
               "msIO_needBinaryStdin()");
606
    return (MS_FAILURE);
607
  }
608
#endif
609

610
  return MS_SUCCESS;
159✔
611
}
612

613
/* ==================================================================== */
614
/*      memory buffer io handling functions.                            */
615
/* ==================================================================== */
616

617
/************************************************************************/
618
/*                         msIO_resetHandlers()                         */
619
/************************************************************************/
620

621
void msIO_resetHandlers()
×
622

623
{
624
  msIOContextGroup *group = msIO_GetContextGroup();
×
625

626
  if (group == NULL)
×
627
    return;
628

629
  if (strcmp(group->stdin_context.label, "buffer") == 0) {
×
630
    msIOBuffer *buf = (msIOBuffer *)group->stdin_context.cbData;
×
631

632
    if (buf->data != NULL)
×
633
      free(buf->data);
×
634
    free(buf);
×
635
  }
636

637
  if (strcmp(group->stdout_context.label, "buffer") == 0) {
×
638
    msIOBuffer *buf = (msIOBuffer *)group->stdout_context.cbData;
×
639

640
    if (buf->data != NULL)
×
641
      free(buf->data);
×
642
    free(buf);
×
643
  }
644

645
  if (strcmp(group->stderr_context.label, "buffer") == 0) {
×
646
    msIOBuffer *buf = (msIOBuffer *)group->stderr_context.cbData;
×
647

648
    if (buf->data != NULL)
×
649
      free(buf->data);
×
650
    free(buf);
×
651
  }
652

653
  msIO_installHandlers(NULL, NULL, NULL);
×
654
}
655

656
/************************************************************************/
657
/*                     msIO_installStdoutToBuffer()                     */
658
/************************************************************************/
659

660
void msIO_installStdoutToBuffer()
34✔
661

662
{
663
  msIOContextGroup *group = msIO_GetContextGroup();
34✔
664
  msIOContext context;
665

666
  context.label = "buffer";
34✔
667
  context.write_channel = MS_TRUE;
34✔
668
  context.readWriteFunc = msIO_bufferWrite;
34✔
669
  context.cbData = calloc(1, sizeof(msIOBuffer));
34✔
670

671
  msIO_installHandlers(&group->stdin_context, &context, &group->stderr_context);
34✔
672
}
34✔
673

674
/************************************************************************/
675
/*               msIO_pushStdoutToBufferAndGetOldContext()              */
676
/*                                                                      */
677
/* This function installs a temporary buffer I/O context and returns    */
678
/* previously installed stdout handler. This previous stdout handler    */
679
/* should later be restored with msIO_restoreOldStdoutContext().        */
680
/* This function can be for example used when wanting to ingest into    */
681
/* libxml objects XML generated by msIO_fprintf()                       */
682
/************************************************************************/
683

684
msIOContext *msIO_pushStdoutToBufferAndGetOldContext()
30✔
685

686
{
687
  msIOContextGroup *group = msIO_GetContextGroup();
30✔
688
  msIOContext *old_context;
689

690
  /* Backup current context */
691
  old_context = (msIOContext *)msSmallMalloc(sizeof(msIOContext));
30✔
692
  memcpy(old_context, &group->stdout_context, sizeof(msIOContext));
30✔
693

694
  msIO_installStdoutToBuffer();
30✔
695

696
  return old_context;
30✔
697
}
698

699
/************************************************************************/
700
/*                    msIO_restoreOldStdoutContext()                    */
701
/************************************************************************/
702

703
void msIO_restoreOldStdoutContext(msIOContext *context_to_restore) {
30✔
704
  msIOContextGroup *group = msIO_GetContextGroup();
30✔
705
  msIOContext *prev_context = &group->stdout_context;
706
  msIOBuffer *buffer;
707

708
  /* Free memory associated to our temporary context */
709
  assert(strcmp(prev_context->label, "buffer") == 0);
710

711
  buffer = (msIOBuffer *)prev_context->cbData;
30✔
712
  msFree(buffer->data);
30✔
713
  msFree(buffer);
30✔
714

715
  /* Restore old context */
716
  msIO_installHandlers(&group->stdin_context, context_to_restore,
30✔
717
                       &group->stderr_context);
718

719
  msFree(context_to_restore);
30✔
720
}
30✔
721

722
/************************************************************************/
723
/*                    msIO_installStdinFromBuffer()                     */
724
/************************************************************************/
725

726
void msIO_installStdinFromBuffer()
×
727

728
{
729
  msIOContextGroup *group = msIO_GetContextGroup();
×
730
  msIOContext context;
731

732
  context.label = "buffer";
×
733
  context.write_channel = MS_FALSE;
×
734
  context.readWriteFunc = msIO_bufferRead;
×
735
  context.cbData = calloc(1, sizeof(msIOBuffer));
×
736

737
  msIO_installHandlers(&context, &group->stdout_context,
×
738
                       &group->stderr_context);
739
}
×
740

741
/************************************************************************/
742
/*              msIO_getAndStripStdoutBufferMimeHeaders()               */
743
/*                                                                      */
744
/************************************************************************/
745

746
hashTableObj *msIO_getAndStripStdoutBufferMimeHeaders() {
2✔
747
  /* -------------------------------------------------------------------- */
748
  /*      Find stdout buffer.                                             */
749
  /* -------------------------------------------------------------------- */
750
  msIOContext *ctx = msIO_getHandler((FILE *)"stdout");
2✔
751
  msIOBuffer *buf;
752
  int start_of_mime_header, current_pos;
753
  hashTableObj *hashTable;
754

755
  if (ctx == NULL || ctx->write_channel == MS_FALSE ||
2✔
756
      strcmp(ctx->label, "buffer") != 0) {
2✔
757
    msSetError(MS_MISCERR, "Can't identify msIO buffer.",
×
758
               "msIO_getAndStripStdoutBufferMimeHeaders");
759
    return NULL;
×
760
  }
761

762
  buf = (msIOBuffer *)ctx->cbData;
2✔
763

764
  hashTable = msCreateHashTable();
2✔
765

766
  /* -------------------------------------------------------------------- */
767
  /*      Loop over all headers.                                          */
768
  /* -------------------------------------------------------------------- */
769
  current_pos = 0;
770
  while (MS_TRUE) {
771
    int pos_of_column = -1;
772
    char *key, *value;
773

774
    start_of_mime_header = current_pos;
775
    while (current_pos < buf->data_offset) {
106✔
776
      if (buf->data[current_pos] == '\r') {
106✔
777
        if (current_pos + 1 == buf->data_offset ||
4✔
778
            buf->data[current_pos + 1] != '\n') {
4✔
779
          pos_of_column = -1;
780
          break;
781
        }
782
        break;
783
      }
784
      if (buf->data[current_pos] == ':') {
102✔
785
        pos_of_column = current_pos;
786
        if (current_pos + 1 == buf->data_offset ||
4✔
787
            buf->data[current_pos + 1] != ' ') {
4✔
788
          pos_of_column = -1;
789
          break;
790
        }
791
      }
792
      current_pos++;
102✔
793
    }
794

795
    if (pos_of_column < 0 || current_pos == buf->data_offset) {
4✔
796
      msSetError(MS_MISCERR, "Corrupt mime headers.",
×
797
                 "msIO_getAndStripStdoutBufferMimeHeaders");
798
      msFreeHashTable(hashTable);
×
799
      return NULL;
×
800
    }
801

802
    key = (char *)malloc(pos_of_column - start_of_mime_header + 1);
4✔
803
    memcpy(key, buf->data + start_of_mime_header,
4✔
804
           pos_of_column - start_of_mime_header);
805
    key[pos_of_column - start_of_mime_header] = '\0';
4✔
806

807
    value = (char *)malloc(current_pos - (pos_of_column + 2) + 1);
4✔
808
    memcpy(value, buf->data + pos_of_column + 2,
4✔
809
           current_pos - (pos_of_column + 2));
810
    value[current_pos - (pos_of_column + 2)] = '\0';
4✔
811

812
    msInsertHashTable(hashTable, key, value);
4✔
813

814
    msFree(key);
4✔
815
    msFree(value);
4✔
816

817
    /* -------------------------------------------------------------------- */
818
    /*      Go to next line.                                                */
819
    /* -------------------------------------------------------------------- */
820
    current_pos += 2;
4✔
821
    if (current_pos == buf->data_offset) {
4✔
822
      msSetError(MS_MISCERR, "Corrupt mime headers.",
×
823
                 "msIO_getAndStripStdoutBufferMimeHeaders");
824
      msFreeHashTable(hashTable);
×
825
      return NULL;
×
826
    }
827

828
    /* If next line is a '\r', this is the end of mime headers. */
829
    if (buf->data[current_pos] == '\r') {
4✔
830
      current_pos++;
2✔
831
      if (current_pos == buf->data_offset || buf->data[current_pos] != '\n') {
2✔
832
        msSetError(MS_MISCERR, "Corrupt mime headers.",
×
833
                   "msIO_getAndStripStdoutBufferMimeHeaders");
834
        msFreeHashTable(hashTable);
×
835
        return NULL;
×
836
      }
837
      current_pos++;
2✔
838
      break;
839
    }
840
  }
841

842
  /* -------------------------------------------------------------------- */
843
  /*      Move data to front of buffer, and reset length.                 */
844
  /* -------------------------------------------------------------------- */
845
  memmove(buf->data, buf->data + current_pos, buf->data_offset - current_pos);
2✔
846
  buf->data[buf->data_offset - current_pos] = '\0';
2✔
847
  buf->data_offset -= current_pos;
2✔
848

849
  return hashTable;
2✔
850
}
851

852
/************************************************************************/
853
/*                 msIO_stripStdoutBufferContentType()                  */
854
/*                                                                      */
855
/*      Strip off Content-Type header from buffer, and return to        */
856
/*      caller.  Returned string is the callers responsibility to       */
857
/*      call msFree() on to deallocate.  This function will return      */
858
/*      NULL if there is no Content-Type header.                        */
859
/************************************************************************/
860

861
char *msIO_stripStdoutBufferContentType()
1✔
862

863
{
864
  /* -------------------------------------------------------------------- */
865
  /*      Find stdout buffer.                                             */
866
  /* -------------------------------------------------------------------- */
867
  msIOContext *ctx = msIO_getHandler((FILE *)"stdout");
1✔
868
  msIOBuffer *buf;
869
  char *content_type = NULL;
870
  int end_of_ct, start_of_data;
871

872
  if (ctx == NULL || ctx->write_channel == MS_FALSE ||
1✔
873
      strcmp(ctx->label, "buffer") != 0) {
1✔
874
    msSetError(MS_MISCERR, "Can't identify msIO buffer.",
×
875
               "msIO_stripStdoutBufferContentType");
876
    return NULL;
×
877
  }
878

879
  buf = (msIOBuffer *)ctx->cbData;
1✔
880

881
  /* -------------------------------------------------------------------- */
882
  /*      Return NULL if we don't have a Content-Type header.             */
883
  /* -------------------------------------------------------------------- */
884
  if (buf->data_offset < 14 ||
1✔
885
      strncasecmp((const char *)buf->data, "Content-Type: ", 14) != 0)
1✔
886
    return NULL;
887

888
  /* -------------------------------------------------------------------- */
889
  /*      Find newline marker at end of content type argument.            */
890
  /* -------------------------------------------------------------------- */
891
  end_of_ct = 13;
892
  while (end_of_ct + 1 < buf->data_offset && buf->data[end_of_ct + 1] != '\r')
43✔
893
    end_of_ct++;
894

895
  if (end_of_ct + 1 == buf->data_offset) {
1✔
896
    msSetError(MS_MISCERR, "Corrupt Content-Type header.",
×
897
               "msIO_stripStdoutBufferContentType");
898
    return NULL;
×
899
  }
900

901
  /* -------------------------------------------------------------------- */
902
  /*      Continue on to the start of data ...                            */
903
  /*      Go to next line and skip if empty.                              */
904
  /* -------------------------------------------------------------------- */
905
  start_of_data = end_of_ct + 3;
1✔
906
  if (start_of_data < buf->data_offset && buf->data[start_of_data] == '\r')
1✔
907
    start_of_data += 2;
1✔
908

909
  if (start_of_data == buf->data_offset) {
1✔
910
    msSetError(MS_MISCERR, "Corrupt Content-Type header.",
×
911
               "msIO_stripStdoutBufferContentType");
912
    return NULL;
×
913
  }
914

915
  /* -------------------------------------------------------------------- */
916
  /*      Copy out content type. Note we go against the coding guidelines */
917
  /*      here and use strncpy() instead of strlcpy() as the source       */
918
  /*      buffer may not be NULL terminated - strlcpy() requires NULL     */
919
  /*      terminated sources (see issue #4672).                           */
920
  /* -------------------------------------------------------------------- */
921
  content_type = (char *)malloc(end_of_ct - 14 + 2);
1✔
922
  strncpy(content_type, (const char *)buf->data + 14, end_of_ct - 14 + 2);
1✔
923
  content_type[end_of_ct - 14 + 1] = '\0';
1✔
924

925
  /* -------------------------------------------------------------------- */
926
  /*      Move data to front of buffer, and reset length.                 */
927
  /* -------------------------------------------------------------------- */
928
  memmove(buf->data, buf->data + start_of_data,
1✔
929
          buf->data_offset - start_of_data);
1✔
930
  buf->data[buf->data_offset - start_of_data] = '\0';
1✔
931
  buf->data_offset -= start_of_data;
1✔
932

933
  return content_type;
1✔
934
}
935

936
/************************************************************************/
937
/*                 msIO_stripStdoutBufferContentHeaders()               */
938
/*                                                                      */
939
/*      Strip off Content-* headers from buffer.                        */
940
/************************************************************************/
941

942
void msIO_stripStdoutBufferContentHeaders() {
2✔
943
  /* -------------------------------------------------------------------- */
944
  /*      Find stdout buffer.                                             */
945
  /* -------------------------------------------------------------------- */
946
  msIOContext *ctx = msIO_getHandler((FILE *)"stdout");
2✔
947
  msIOBuffer *buf;
948
  int start_of_data;
949

950
  if (ctx == NULL || ctx->write_channel == MS_FALSE ||
2✔
951
      strcmp(ctx->label, "buffer") != 0) {
2✔
952
    msSetError(MS_MISCERR, "Can't identify msIO buffer.",
×
953
               "msIO_stripStdoutBufferContentHeaders");
954
    return;
×
955
  }
956

957
  buf = (msIOBuffer *)ctx->cbData;
2✔
958

959
  /* -------------------------------------------------------------------- */
960
  /*      Exit if we don't have any content-* header.                     */
961
  /* -------------------------------------------------------------------- */
962
  if (buf->data_offset < 8 ||
2✔
963
      strncasecmp((const char *)buf->data, "Content-", 8) != 0)
2✔
964
    return;
965

966
  /* -------------------------------------------------------------------- */
967
  /*      Loop over all content-* headers.                                */
968
  /* -------------------------------------------------------------------- */
969
  start_of_data = 0;
970
  while (buf->data_offset > start_of_data &&
2✔
971
         strncasecmp((const char *)buf->data + start_of_data, "Content-", 8) ==
2✔
972
             0) {
973
    /* -------------------------------------------------------------------- */
974
    /*      Find newline marker at end of content-* header argument.        */
975
    /* -------------------------------------------------------------------- */
976
    start_of_data += 7;
1✔
977
    while (start_of_data + 1 < buf->data_offset &&
49✔
978
           buf->data[start_of_data + 1] != '\r')
49✔
979
      start_of_data++;
980

981
    if (start_of_data + 1 == buf->data_offset) {
1✔
982
      msSetError(MS_MISCERR, "Corrupt Content-* header.",
×
983
                 "msIO_stripStdoutBufferContentHeaders");
984
      return;
×
985
    }
986
    /* -------------------------------------------------------------------- */
987
    /*      Go to next line.                                                */
988
    /* -------------------------------------------------------------------- */
989
    start_of_data += 3;
1✔
990
  }
991

992
  /* -------------------------------------------------------------------- */
993
  /*      Continue on to the start of data ...                            */
994
  /*      Skip next line if empty.                                        */
995
  /* -------------------------------------------------------------------- */
996
  if (start_of_data < buf->data_offset && buf->data[start_of_data] == '\r')
1✔
997
    start_of_data += 2;
1✔
998

999
  if (start_of_data == buf->data_offset) {
1✔
1000
    msSetError(MS_MISCERR, "Corrupt Content-* header.",
×
1001
               "msIO_stripStdoutBufferContentHeaders");
1002
    return;
×
1003
  }
1004

1005
  /* -------------------------------------------------------------------- */
1006
  /*      Move data to front of buffer, and reset length.                 */
1007
  /* -------------------------------------------------------------------- */
1008
  memmove(buf->data, buf->data + start_of_data,
1✔
1009
          buf->data_offset - start_of_data);
1✔
1010
  buf->data[buf->data_offset - start_of_data] = '\0';
1✔
1011
  buf->data_offset -= start_of_data;
1✔
1012

1013
  return;
1✔
1014
}
1015

1016
/************************************************************************/
1017
/*                          msIO_bufferWrite()                          */
1018
/************************************************************************/
1019

1020
int msIO_bufferWrite(void *cbData, void *data, int byteCount)
911✔
1021

1022
{
1023
  msIOBuffer *buf = (msIOBuffer *)cbData;
1024

1025
  /*
1026
  ** Grow buffer if needed (reserve one extra byte to put nul character)
1027
  */
1028
  if (buf->data_offset + byteCount >= buf->data_len) {
911✔
1029
    buf->data_len = buf->data_len * 2 + byteCount + 100;
126✔
1030
    if (buf->data == NULL)
126✔
1031
      buf->data = (unsigned char *)malloc(buf->data_len);
37✔
1032
    else
1033
      buf->data = (unsigned char *)realloc(buf->data, buf->data_len);
89✔
1034

1035
    if (buf->data == NULL) {
126✔
1036
      msSetError(MS_MEMERR, "Failed to allocate %d bytes for capture buffer.",
×
1037
                 "msIO_bufferWrite()", buf->data_len);
1038
      buf->data_len = 0;
×
1039
      return 0;
×
1040
    }
1041
  }
1042

1043
  /*
1044
  ** Copy result into buffer.
1045
  */
1046

1047
  memcpy(buf->data + buf->data_offset, data, byteCount);
911✔
1048
  buf->data_offset += byteCount;
911✔
1049
  buf->data[buf->data_offset] = '\0';
911✔
1050

1051
  return byteCount;
911✔
1052
}
1053

1054
/************************************************************************/
1055
/*                          msIO_bufferRead()                           */
1056
/************************************************************************/
1057

1058
int msIO_bufferRead(void *cbData, void *data, int byteCount)
×
1059

1060
{
1061
  (void)cbData;
1062
  (void)data;
1063
  (void)byteCount;
1064
  /* not implemented yet. */
1065
  return 0;
×
1066
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc