~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to proxy/InkXml.cc

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
4
 
 
5
  @section license License
 
6
 
 
7
  Licensed to the Apache Software Foundation (ASF) under one
 
8
  or more contributor license agreements.  See the NOTICE file
 
9
  distributed with this work for additional information
 
10
  regarding copyright ownership.  The ASF licenses this file
 
11
  to you under the Apache License, Version 2.0 (the
 
12
  "License"); you may not use this file except in compliance
 
13
  with the License.  You may obtain a copy of the License at
 
14
 
 
15
      http://www.apache.org/licenses/LICENSE-2.0
 
16
 
 
17
  Unless required by applicable law or agreed to in writing, software
 
18
  distributed under the License is distributed on an "AS IS" BASIS,
 
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
20
  See the License for the specific language governing permissions and
 
21
  limitations under the License.
 
22
 */
 
23
 
 
24
/***************************************************************************
 
25
 InkXml.cc
 
26
 
 
27
 
 
28
 ***************************************************************************/
 
29
#include "libts.h"
 
30
 
 
31
#include "InkXml.h"
 
32
 
 
33
/*--- for stand-alone testing
 
34
#define xstrdup strdup
 
35
#define xfree free
 
36
#define xmalloc malloc
 
37
#define NEW(x) x
 
38
#define ink_isspace isspace
 
39
---*/
 
40
 
 
41
/*-------------------------------------------------------------------------
 
42
  InkXmlAttr
 
43
  -------------------------------------------------------------------------*/
 
44
 
 
45
InkXmlAttr::InkXmlAttr(char *tag, char *value)
 
46
{
 
47
  m_tag = xstrdup(tag);
 
48
  m_value = xstrdup(value);
 
49
}
 
50
 
 
51
InkXmlAttr::~InkXmlAttr()
 
52
{
 
53
  xfree(m_tag);
 
54
  xfree(m_value);
 
55
}
 
56
 
 
57
void
 
58
InkXmlAttr::display(FILE * fd)
 
59
{
 
60
  fprintf(fd, "    <%s,%s>\n", m_tag, m_value);
 
61
}
 
62
 
 
63
/*-------------------------------------------------------------------------
 
64
  InkXmlObject
 
65
  -------------------------------------------------------------------------*/
 
66
 
 
67
InkXmlObject::InkXmlObject(char *object_name, bool dup_attrs_allowed)
 
68
{
 
69
  m_object_name = xstrdup(object_name);
 
70
  m_dup_attrs_allowed = dup_attrs_allowed;
 
71
}
 
72
 
 
73
InkXmlObject::~InkXmlObject()
 
74
{
 
75
  xfree(m_object_name);
 
76
  clear_tags();
 
77
}
 
78
 
 
79
void
 
80
InkXmlObject::clear_tags()
 
81
{
 
82
  InkXmlAttr *attr;
 
83
  while ((attr = m_tags.dequeue())) {
 
84
    delete attr;
 
85
  }
 
86
}
 
87
 
 
88
int
 
89
InkXmlObject::add_tag(char *tag, char *value)
 
90
{
 
91
  ink_assert(tag != NULL);
 
92
  ink_assert(value != NULL);
 
93
 
 
94
  InkXmlAttr *attr = NEW(new InkXmlAttr(tag, value));
 
95
  return add_attr(attr);
 
96
}
 
97
 
 
98
int
 
99
InkXmlObject::add_attr(InkXmlAttr * attr)
 
100
{
 
101
  ink_assert(attr != NULL);
 
102
 
 
103
  if (!m_dup_attrs_allowed) {
 
104
    for (InkXmlAttr * a = first(); a; a = next(a)) {
 
105
      if (!strcmp(a->tag(), attr->tag())) {
 
106
        Debug("xml", "tag %s already exists & dups not allowed", attr->tag());
 
107
        return -1;
 
108
      }
 
109
    }
 
110
  }
 
111
  m_tags.enqueue(attr);
 
112
  return 0;
 
113
}
 
114
 
 
115
char *
 
116
InkXmlObject::tag_value(char *tag_name)
 
117
{
 
118
  ink_assert(tag_name != NULL);
 
119
 
 
120
  for (InkXmlAttr * a = first(); a; a = next(a)) {
 
121
    if (!strcmp(a->tag(), tag_name)) {
 
122
      return a->value();
 
123
    }
 
124
  }
 
125
  return NULL;
 
126
}
 
127
 
 
128
void
 
129
InkXmlObject::display(FILE * fd)
 
130
{
 
131
  fprintf(fd, "<%s>\n", m_object_name);
 
132
  for (InkXmlAttr * a = first(); a; a = next(a)) {
 
133
    a->display(fd);
 
134
  }
 
135
}
 
136
 
 
137
/*-------------------------------------------------------------------------
 
138
  InkXmlConfigFile
 
139
  -------------------------------------------------------------------------*/
 
140
 
 
141
InkXmlConfigFile::InkXmlConfigFile(char *config_file):
 
142
m_line(0),
 
143
m_col(0)
 
144
{
 
145
  m_config_file = xstrdup(config_file);
 
146
}
 
147
 
 
148
InkXmlConfigFile::~InkXmlConfigFile()
 
149
{
 
150
  xfree(m_config_file);
 
151
  clear_objects();
 
152
}
 
153
 
 
154
void
 
155
InkXmlConfigFile::clear_objects()
 
156
{
 
157
  InkXmlObject *obj;
 
158
  while ((obj = m_objects.dequeue())) {
 
159
    delete obj;
 
160
  }
 
161
}
 
162
 
 
163
/*                                                                  */
 
164
int
 
165
InkXmlConfigFile::parse(int fd)
 
166
{
 
167
  ink_assert(fd >= 0);
 
168
  Debug("log", "Parsing XML config info from memory..");
 
169
 
 
170
  m_line = 1;
 
171
  m_col = 0;
 
172
 
 
173
  InkXmlObject *obj;
 
174
  while ((obj = get_next_xml_object(fd)) != NULL) {
 
175
    Debug("log", "Adding XML object <%s>", obj->object_name());
 
176
    add_object(obj);
 
177
  }
 
178
 
 
179
  return 0;
 
180
}
 
181
 
 
182
/*                                                                  */
 
183
 
 
184
int
 
185
InkXmlConfigFile::parse()
 
186
{
 
187
  ink_assert(m_config_file != NULL);
 
188
  Debug("xml", "Parsing XML config file %s ...", m_config_file);
 
189
 
 
190
  int fd =::open(m_config_file, O_RDONLY);
 
191
  if (fd < 0) {
 
192
    Debug("xml", "Error opening %s: %d, %s", m_config_file, fd, strerror(errno));
 
193
    return -1;
 
194
  }
 
195
 
 
196
  m_line = 1;
 
197
  m_col = 0;
 
198
 
 
199
  InkXmlObject *obj;
 
200
  while ((obj = get_next_xml_object(fd)) != NULL) {
 
201
    Debug("xml", "Adding XML object <%s>", obj->object_name());
 
202
    add_object(obj);
 
203
  }
 
204
 
 
205
  ::close(fd);
 
206
  return 0;
 
207
}
 
208
 
 
209
InkXmlObject *
 
210
InkXmlConfigFile::find_object(char *object_name)
 
211
{
 
212
  for (InkXmlObject * obj = first(); obj; obj = next(obj)) {
 
213
    if (!strcmp(object_name, obj->object_name())) {
 
214
      return obj;
 
215
    }
 
216
  }
 
217
  return NULL;
 
218
}
 
219
 
 
220
void
 
221
InkXmlConfigFile::display(FILE * fd)
 
222
{
 
223
  size_t i;
 
224
 
 
225
  fprintf(fd, "\n");
 
226
  for (i = 0; i < strlen(m_config_file) + 13; i++)
 
227
    fputc('-', fd);
 
228
  fprintf(fd, "\nConfig File: %s\n", m_config_file);
 
229
  for (i = 0; i < strlen(m_config_file) + 13; i++)
 
230
    fputc('-', fd);
 
231
  fprintf(fd, "\n");
 
232
  for (InkXmlObject * obj = first(); obj; obj = next(obj)) {
 
233
    obj->display(fd);
 
234
    fprintf(fd, "\n");
 
235
  }
 
236
}
 
237
 
 
238
void
 
239
InkXmlConfigFile::add_object(InkXmlObject * object)
 
240
{
 
241
  ink_assert(object != NULL);
 
242
  m_objects.enqueue(object);
 
243
}
 
244
 
 
245
/*-------------------------------------------------------------------------
 
246
  InkXmlConfigFile::get_next_xml_object()
 
247
 
 
248
  This routine (and its friends) does the real work of parsing the given
 
249
  open file for the next XML object.
 
250
  -------------------------------------------------------------------------*/
 
251
 
 
252
InkXmlObject *
 
253
InkXmlConfigFile::get_next_xml_object(int fd)
 
254
{
 
255
  ink_assert(fd >= 0);
 
256
 
 
257
  char token;
 
258
  bool start_object = false;
 
259
 
 
260
  while ((token = next_token(fd)) != EOF) {
 
261
    switch (token) {
 
262
 
 
263
    case '<':
 
264
      start_object = true;
 
265
      break;
 
266
 
 
267
    case '!':
 
268
      if (!start_object)
 
269
        return parse_error();
 
270
      if ((token = scan_comment(fd)) == EOF) {
 
271
        return NULL;
 
272
      }
 
273
      Debug("xml", "comment scanned");
 
274
      start_object = false;
 
275
      break;
 
276
 
 
277
    default:
 
278
      if (!start_object)
 
279
        return parse_error();
 
280
      return scan_object(fd, token);
 
281
    }
 
282
  }
 
283
  return NULL;
 
284
}
 
285
 
 
286
InkXmlObject *
 
287
InkXmlConfigFile::parse_error()
 
288
{
 
289
  Debug("xml", "Invalid XML tag, line %u, col %u", m_line, m_col);
 
290
  return NULL;
 
291
}
 
292
 
 
293
#define BAD_ATTR ((InkXmlAttr*)1)
 
294
 
 
295
InkXmlObject *
 
296
InkXmlConfigFile::scan_object(int fd, char token)
 
297
{
 
298
  // this routine is called just after the first '<' is read for a new
 
299
  // object.
 
300
 
 
301
  const int max_ident_len = 2048;
 
302
  char ident[max_ident_len];
 
303
  int ident_len = 0;
 
304
 
 
305
  while (token != '>' && ident_len < max_ident_len) {
 
306
    ident[ident_len++] = token;
 
307
    token = next_token(fd);
 
308
    if (token == EOF)
 
309
      return parse_error();
 
310
  }
 
311
  if (!ident_len || ident_len >= max_ident_len) {
 
312
    return parse_error();
 
313
  }
 
314
 
 
315
  ident[ident_len] = 0;
 
316
  InkXmlObject *obj = new InkXmlObject(ident);
 
317
  ink_assert(obj != NULL);
 
318
 
 
319
  InkXmlAttr *attr;
 
320
  while ((attr = scan_attr(fd, ident)) != NULL) {
 
321
    if (attr == BAD_ATTR) {
 
322
      return parse_error();
 
323
    }
 
324
    obj->add_attr(attr);
 
325
  }
 
326
 
 
327
  return obj;
 
328
}
 
329
 
 
330
InkXmlAttr *
 
331
InkXmlConfigFile::scan_attr(int fd, char *id)
 
332
{
 
333
  // this routine is called after the object identifier has been scannedm
 
334
  // and should attempt to scan for the next attribute set.  When we see
 
335
  // the end of the object (closing identifier), we scan it and return
 
336
  // NULL for the attribute, signalling that there are no more
 
337
  // attributes.
 
338
 
 
339
  char token, prev, next;
 
340
  const int buf_size = 2048;
 
341
  char name[buf_size];
 
342
  char value[buf_size];
 
343
  char ident[buf_size];
 
344
  char *write_to = NULL;
 
345
  int write_len = 0;
 
346
  bool start_attr = false;
 
347
  bool in_quotes = false;
 
348
  InkXmlAttr *attr = NULL;
 
349
 
 
350
  prev = next = 0;
 
351
  while ((token = next_token(fd, !in_quotes)) != EOF) {
 
352
    switch (token) {
 
353
    case '<':
 
354
      if (in_quotes && write_to) {
 
355
        if (write_len >= buf_size)
 
356
          return BAD_ATTR;
 
357
        write_to[write_len++] = token;
 
358
        break;
 
359
      }
 
360
      start_attr = true;
 
361
      write_to = name;
 
362
      write_len = 0;
 
363
      break;
 
364
 
 
365
    case '=':
 
366
      if (in_quotes && write_to) {
 
367
        if (write_len >= buf_size)
 
368
          return BAD_ATTR;
 
369
        write_to[write_len++] = token;
 
370
        break;
 
371
      }
 
372
      if (!start_attr)
 
373
        return BAD_ATTR;
 
374
      write_to[write_len] = 0;
 
375
      write_to = value;
 
376
      write_len = 0;
 
377
      break;
 
378
 
 
379
    case '"':
 
380
      if (in_quotes) {
 
381
        if (prev == '\\') {
 
382
          // escape the quote, just replace the backslash
 
383
          // with it
 
384
          write_to[write_len - 1] = token;
 
385
          break;
 
386
        }
 
387
      }
 
388
      in_quotes = !in_quotes;
 
389
      break;
 
390
 
 
391
    case '/':
 
392
      if (in_quotes && write_to) {
 
393
        if (write_len >= buf_size)
 
394
          return BAD_ATTR;
 
395
        write_to[write_len++] = token;
 
396
        break;
 
397
      }
 
398
      if (!start_attr)
 
399
        return BAD_ATTR;
 
400
      if (prev == '<') {
 
401
        write_len = 0;
 
402
        token = next_token(fd, !in_quotes);
 
403
        while (token != '>' && write_len < buf_size) {
 
404
          ident[write_len++] = token;
 
405
          token = next_token(fd, !in_quotes);
 
406
          if (token == EOF)
 
407
            return BAD_ATTR;
 
408
        }
 
409
        if (!write_len || write_len >= buf_size) {
 
410
          return BAD_ATTR;
 
411
        }
 
412
        ident[write_len] = 0;
 
413
        if (strcmp(ident, id) != 0)
 
414
          return BAD_ATTR;
 
415
        return NULL;
 
416
      }
 
417
 
 
418
      next = next_token(fd, !in_quotes);
 
419
      if (next != '>')
 
420
        return BAD_ATTR;
 
421
      write_to[write_len] = 0;
 
422
      attr = new InkXmlAttr(name, value);
 
423
      ink_assert(attr != NULL);
 
424
      return attr;
 
425
 
 
426
    case '>':
 
427
      if (in_quotes && write_to) {
 
428
        if (write_len >= buf_size)
 
429
          return BAD_ATTR;
 
430
        write_to[write_len++] = token;
 
431
        break;
 
432
      }
 
433
      // seen at this point, this is an error, probably becase
 
434
      // the person forgot the trailing '/'.
 
435
      return BAD_ATTR;
 
436
 
 
437
    default:
 
438
      if (!start_attr)
 
439
        return BAD_ATTR;
 
440
      if (write_len >= buf_size)
 
441
        return BAD_ATTR;
 
442
      write_to[write_len++] = token;
 
443
      break;
 
444
    }
 
445
    prev = token;
 
446
  }
 
447
  return BAD_ATTR;
 
448
}
 
449
 
 
450
char
 
451
InkXmlConfigFile::next_token(int fd, bool eat_whitespace)
 
452
{
 
453
  char ch;
 
454
  while (read(fd, &ch, 1) == 1) {
 
455
    if (ch == '\n') {
 
456
      m_line++;
 
457
      m_col = 0;
 
458
      continue;
 
459
    }
 
460
    m_col++;
 
461
    if (eat_whitespace && ParseRules::is_space(ch))
 
462
      continue;
 
463
    return ch;
 
464
  }
 
465
  return EOF;
 
466
}
 
467
 
 
468
char
 
469
InkXmlConfigFile::scan_comment(int fd)
 
470
{
 
471
  // this routine is called when we're just past a "<!" in the file.  we
 
472
  // need to skip until we find the matching '>'.
 
473
 
 
474
  int lt_stack = 1;             // we've already seen one '<' character
 
475
  char token;
 
476
  while ((token = next_token(fd)) != EOF) {
 
477
    switch (token) {
 
478
    case '<':
 
479
      lt_stack++;
 
480
      break;
 
481
    case '>':
 
482
      lt_stack--;
 
483
      if (lt_stack == 0) {
 
484
        return token;
 
485
      }
 
486
      break;
 
487
    default:
 
488
      break;
 
489
    }
 
490
  }
 
491
  return EOF;
 
492
}