HttpProcessUtility::readQualityValue()   B
last analyzed

Complexity

Conditions 9
Paths 11

Size

Total Lines 42
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 9.648

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 30
c 1
b 0
f 0
dl 0
loc 42
ccs 24
cts 30
cp 0.8
rs 8.0555
cc 9
nc 11
nop 3
crap 9.648
1
<?php
2
3
namespace POData;
4
5
use POData\Common\Messages;
6
use POData\Common\HttpHeaderFailure;
7
use POData\Providers\Metadata\Type\Char;
8
9
10
/**
11
 * Class MediaType
12
 *
13
 * The Accept request-header field can be used to specify certain
14
 * media types which are acceptable for the response, this class
15
 * is used to hold details of such media type.
16
 * http://www.w3.org/Protocols/rfc1341/4_Content-Type.html
17
 *
18
 * @package POData
19
 */
20
class MediaType
21
{
22
    /**
23
     * The type part of media type.
24
     *
25
     * @var string
26
     */
27
    private $_type;
28
29
    /**
30
     * The sub-type part of media type.
31
     *
32
     * @var string
33
     */
34
    private $_subType;
35
36
    /**
37
     * The parameters associated with the media type.
38
     *
39
     * @var array(array(string, string))
40
     */
41
    private $_parameters;
42
43
    /**
44
     * Constructs a new instance of Media Type.
45
     *
46
     * @param string $type       The type of media type
47
     * @param string $subType    The sub type of media type
48
     * @param array  $parameters The parameters associated with media type
49
     *
50
     * @return void
51
     */
52 158
    public function  __construct($type, $subType, $parameters)
53
    {
54 158
        $this->_type = $type;
55 158
        $this->_subType = $subType;
56 158
        $this->_parameters = $parameters;
57
    }
58
59
    /**
60
     * Gets the MIME type.
61
     *
62
     * @return string
63
     */
64
    public function getMimeType()
65
    {
66
        return $this->_type . '/' . $this->_subType;
67
    }
68
69
    /**
70
     * Gets the parameters associated with the media types.
71
     *
72
     * @return array(array(string, string))
73
     */
74
    public function getParameters()
75
    {
76
        return $this->_parameters;
77
    }
78
79
    /**
80
     * Gets the number of parts in this media type that matches with
81
     * the given candidate type.
82
     *
83
     * @param string $candidate The candidate mime type.
84
     *
85
     * @return int Returns -1 if this media type does not match with the
86
     *                        candidate media type, 0 if media type's type is '*'
87
     *                        (accept all types), 1 if media types's type matches
88
     *                        with the candidate MIME type's type and media type's
89
     *                        sub-types is '*' (accept all sub-type), 2 if both
90
     *                        type and sub-type matches.
91
     */
92 157
    public function getMatchingRating($candidate)
93
    {
94 157
        $result = -1;
95 157
        if (strlen($candidate) > 0) {
96
97
            //get the odata parameter (if there is one)
98 157
            $candidateODataValue = null;
99 157
            $candidateParts = explode(';', $candidate);
100 157
            if (count($candidateParts) > 1) {
101
                //is it safe to assume the mime type is always the first part?
102 129
                $candidate = array_shift($candidateParts); //move off the first type matcher
103
                //the rest look like QSPs..kinda so we can do this
104 129
                parse_str(implode("&", $candidateParts), $candidateParts);
105 129
                if (array_key_exists('odata', $candidateParts)) {
106 129
                    $candidateODataValue = $candidateParts['odata'];
107
                }
108
            }
109
110
            //ensure that the odata parameter values match
111 157
            if ($this->getODataValue() !== $candidateODataValue) {
112 143
                return -1;
113
            }
114
115
116 143
            if ($this->_type == '*') {
117
                $result = 0;
118
            } else {
119 143
                $separatorIdx = strpos($candidate, '/');
120 143
                if ($separatorIdx !== false) {
121
                    //if there's a subtype..look further
122 143
                    $candidateType = substr($candidate, 0, $separatorIdx);
123 143
                    if (strcasecmp($this->_type, $candidateType) == 0) {
124
                        //If main type matches
125 143
                        if ($this->_subType == '*') {
126
                            //and sub type matches with wildcard
127
                            $result = 1;
128
                        } else {
129 143
                            $candidateSubType = substr($candidate, strlen($candidateType) + 1);
130 143
                            if (strcasecmp($this->_subType, $candidateSubType) == 0) {
131
                                //if sub type matches
132 136
                                $result = 2;
133
134
                            }
135
                        }
136
                    }
137
                }
138
            }
139
        }
140
141 143
        return $result;
142
    }
143
144 157
    public function getODataValue()
145
    {
146 157
        foreach ($this->_parameters as $parameter) {
147 131
            foreach ($parameter as $key => $value) {
148 131
                if (strcasecmp($key, 'odata') === 0) {
149 94
                    return $value;
150
                }
151
            }
152
        }
153
154 63
        return null;
155
    }
156
157
    /**
158
     * Gets the quality factor associated with this media type.
159
     *
160
     * @return int The value associated with 'q' parameter (0-1000),
161
     *             if absent return 1000.
162
     */
163 136
    public function getQualityValue()
164
    {
165 136
        foreach ($this->_parameters as $parameter) {
166 117
            foreach ($parameter as $key => $value) {
167 117
                if (strcasecmp($key, 'q') === 0) {
168 45
                    $textIndex = 0;
169
                    $result;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result seems to be never defined.
Loading history...
170 45
                    HttpProcessUtility::readQualityValue(
171 45
                        $value,
172 45
                        $textIndex,
173 45
                        $result
174 45
                    );
175 45
                    return $result;
176
                }
177
            }
178
        }
179
180 91
        return 1000;
181
    }
182
}
183
184
/**
185
 * Class HttpProcessUtility
186
 * @package POData
187
 */
188
class HttpProcessUtility
189
{
190
191
    /**
192
     * Gets the appropriate MIME type for the request, throwing if there is none.
193
     *
194
     * @param string        $acceptTypesText    Text as it appears in an HTTP
195
     *                                          Accepts header.
196
     * @param string[] $exactContentTypes  Preferred content type to match if an exact media type is given - this is in descending order of preference.
197
     *
198
     * @param string        $inexactContentType Preferred fallback content type for inexact matches.
199
     *
200
     * @return string One of exactContentType or inexactContentType.
201
     */
202
    public static function selectRequiredMimeType($acceptTypesText,
203
        $exactContentTypes,
204
        $inexactContentType
205
    ) {
206
        $selectedContentType = null;
207
        $selectedMatchingParts = -1;
208
        $selectedQualityValue = 0;
209
        $acceptable = false;
210
        $acceptTypesEmpty = true;
211
        $foundExactMatch = false;
212
213
        if (!is_null($acceptTypesText)) {
0 ignored issues
show
introduced by
The condition is_null($acceptTypesText) is always false.
Loading history...
214
            $acceptTypes = self::mimeTypesFromAcceptHeaders($acceptTypesText);
215
            foreach ($acceptTypes as $acceptType) {
216
                $acceptTypesEmpty = false;
217
                foreach ($exactContentTypes as $exactContentType) {
218
                    if (strcasecmp($acceptType->getMimeType(), $exactContentType) == 0) {
219
                        $selectedContentType = $exactContentType;
220
                        $selectedQualityValue = $acceptType->getQualityValue();
221
                        $acceptable = $selectedQualityValue != 0;
222
                        $foundExactMatch = true;
223
                        break;
224
                    }
225
                }
226
227
                if ($foundExactMatch) {
228
                    break;
229
                }
230
231
                $matchingParts
232
                    = $acceptType->getMatchingRating($inexactContentType);
233
                if ($matchingParts < 0) {
234
                    continue;
235
                }
236
237
                if ($matchingParts > $selectedMatchingParts) {
238
                    // A more specific type wins.
239
                    $selectedContentType = $inexactContentType;
240
                    $selectedMatchingParts = $matchingParts;
241
                    $selectedQualityValue = $acceptType->getQualityValue();
242
                    $acceptable = $selectedQualityValue != 0;
243
                } else if ($matchingParts == $selectedMatchingParts) {
244
                    // A type with a higher q-value wins.
245
                    $candidateQualityValue = $acceptType->getQualityValue();
246
                    if ($candidateQualityValue > $selectedQualityValue) {
247
                        $selectedContentType = $inexactContentType;
248
                        $selectedQualityValue = $candidateQualityValue;
249
                        $acceptable = $selectedQualityValue != 0;
250
                    }
251
                }
252
            }
253
        }
254
255
        if (!$acceptable && !$acceptTypesEmpty) {
256
            throw new HttpHeaderFailure(
257
                Messages::unsupportedMediaType(),
258
                415
259
            );
260
        }
261
262
        if ($acceptTypesEmpty) {
263
            $selectedContentType = $inexactContentType;
264
        }
265
266
        return $selectedContentType;
267
    }
268
269
    /**
270
     * Selects an acceptable MIME type that satisfies the Accepts header.
271
     *
272
     * @param string $acceptTypesText Text for Accepts header.
273
     * @param string[] $availableTypes  Types that the server is willing to return, in descending order of preference.
274
     *
275
     * @return string The best MIME type for the client.
276
     *
277
     * @throws HttpHeaderFailure
278
     */
279 160
    public static function selectMimeType($acceptTypesText, array $availableTypes)
280
    {
281 160
        $selectedContentType = null;
282 160
        $selectedMatchingParts = -1;
283 160
        $selectedQualityValue = 0;
284 160
        $selectedPreferenceIndex = PHP_INT_MAX;
285 160
        $acceptable = false;
286 160
        $acceptTypesEmpty = true;
287 160
        if (!is_null($acceptTypesText)) {
0 ignored issues
show
introduced by
The condition is_null($acceptTypesText) is always false.
Loading history...
288 158
            $acceptTypes = self::mimeTypesFromAcceptHeaders($acceptTypesText);
289 158
            foreach ($acceptTypes as $acceptType) {
290 158
                $acceptTypesEmpty = false;
291 158
                for ($i = 0; $i < count($availableTypes); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
292 157
                    $availableType = $availableTypes[$i];
293 157
                    $matchRating = $acceptType->getMatchingRating($availableType);
294 157
                    if ($matchRating < 0) {
295 152
                        continue;
296
                    }
297
298 136
                    if ($matchRating > $selectedMatchingParts) {
299
                        // A more specific type wins.
300 136
                        $selectedContentType = $availableType;
301 136
                        $selectedMatchingParts = $matchRating;
302 136
                        $selectedQualityValue = $acceptType->getQualityValue();
303 136
                        $selectedPreferenceIndex = $i;
304 136
                        $acceptable = $selectedQualityValue != 0;
305 5
                    } else if ($matchRating == $selectedMatchingParts) {
306
                        // A type with a higher q-value wins.
307 5
                        $candidateQualityValue = $acceptType->getQualityValue();
308 5
                        if ($candidateQualityValue > $selectedQualityValue) {
309 1
                            $selectedContentType = $availableType;
310 1
                            $selectedQualityValue = $candidateQualityValue;
311 1
                            $selectedPreferenceIndex = $i;
312 1
                            $acceptable = $selectedQualityValue != 0;
313 4
                        } else if ($candidateQualityValue == $selectedQualityValue) {
314
                            // A type that is earlier in the availableTypes array wins.
315 2
                            if ($i < $selectedPreferenceIndex) {
316 1
                                $selectedContentType = $availableType;
317 1
                                $selectedPreferenceIndex = $i;
318
                            }
319
                        }
320
                    }
321
                }
322
            }
323
        }
324
325 160
        if ($acceptTypesEmpty) {
326 2
            $selectedContentType = $availableTypes[0];
327 158
        } else if (!$acceptable) {
0 ignored issues
show
introduced by
The condition $acceptable is always false.
Loading history...
328 23
            $selectedContentType = null;
329
        }
330
331 160
        return $selectedContentType;
332
    }
333
334
    /**
335
     * Returns all MIME types from the $text.
336
     *
337
     * @param string $text Text as it appears on an HTTP Accepts header.
338
     *
339
     * @return MediaType[] Array of media (MIME) type description.
340
     *
341
     * @throws HttpHeaderFailure If found any syntax error in the given text.
342
     */
343 158
    public static function mimeTypesFromAcceptHeaders($text)
344
    {
345 158
        $mediaTypes = array();
346 158
        $textIndex = 0;
347 158
        while (!self::skipWhitespace($text, $textIndex)) {
348 158
            $type = null;
349 158
            $subType = null;
350 158
            self::readMediaTypeAndSubtype($text, $textIndex, $type, $subType);
351
352 158
            $parameters = array();
353 158
            while (!self::skipWhitespace($text, $textIndex)) {
354 131
                if ($text[$textIndex] == ',') {
355 8
                    $textIndex++;
356 8
                    break;
357
                }
358
359 131
                if ($text[$textIndex] != ';') {
360
                    throw new HttpHeaderFailure(
361
                        Messages::httpProcessUtilityMediaTypeRequiresSemicolonBeforeParameter(),
362
                        400
363
                    );
364
                }
365
366 131
                $textIndex++;
367 131
                if (self::skipWhitespace($text, $textIndex)) {
368
                    break;
369
                }
370
371 131
                self::readMediaTypeParameter($text, $textIndex, $parameters);
372
            }
373
374 158
            $mediaTypes[] = new MediaType($type, $subType, $parameters);
375
        }
376
377 158
        return $mediaTypes;
378
    }
379
380
    /**
381
     * Skips whitespace in the specified text by advancing an index to
382
     * the next non-whitespace character.
383
     *
384
     * @param string $text       Text to scan.
385
     * @param int    &$textIndex Index to begin scanning from.
386
     *
387
     * @return boolean true if the end of the string was reached, false otherwise.
388
     */
389 158
    public static function skipWhiteSpace($text, &$textIndex)
390
    {
391 158
        $textLen = strlen($text);
392 158
        while (($textIndex < $textLen) && Char::isWhiteSpace($text[$textIndex])) {
393 8
            $textIndex++;
394
        }
395
396 158
        return $textLen == $textIndex;
397
    }
398
399
    /**
400
     * Reads the type and subtype specifications for a MIME type.
401
     *
402
     * @param string $text       Text in which specification exists.
403
     * @param int    &$textIndex Pointer into text.
404
     * @param string &$type      Type of media found.
405
     * @param string &$subType   Subtype of media found.
406
     *
407
     * @throws HttpHeaderFailure If failed to read type and sub-type.
408
     *
409
     * @return void
410
     */
411 158
    public static function readMediaTypeAndSubtype($text, &$textIndex,
412
        &$type, &$subType
413
    ) {
414 158
        $textStart = $textIndex;
415 158
        if (self::readToken($text, $textIndex)) {
416
            throw new HttpHeaderFailure(
417
                Messages::httpProcessUtilityMediaTypeUnspecified(),
418
                400
419
            );
420
        }
421
422 158
        if ($text[$textIndex] != '/') {
423
            throw new HttpHeaderFailure(
424
                Messages::httpProcessUtilityMediaTypeRequiresSlash(),
425
                400
426
            );
427
        }
428
429 158
        $type = substr($text, $textStart, $textIndex - $textStart);
430 158
        $textIndex++;
431
432 158
        $subTypeStart = $textIndex;
433 158
        self::readToken($text, $textIndex);
434 158
        if ($textIndex == $subTypeStart) {
435
            throw new HttpHeaderFailure(
436
                Messages::httpProcessUtilityMediaTypeRequiresSubType(),
437
                400
438
            );
439
        }
440
441 158
        $subType = substr($text, $subTypeStart, $textIndex - $subTypeStart);
442
    }
443
444
    /**
445
     * Reads a token on the specified text by advancing an index on it.
446
     *
447
     * @param string $text       Text to read token from.
448
     * @param int    &$textIndex Index for the position being scanned on text.
449
     *
450
     * @return boolean true if the end of the text was reached; false otherwise.
451
     */
452 158
    public static function readToken($text, &$textIndex)
453
    {
454 158
        $textLen = strlen($text);
455 158
        while (($textIndex < $textLen) && self::isHttpTokenChar($text[$textIndex])) {
456 158
            $textIndex++;
457
        }
458
459 158
        return $textLen == $textIndex;
460
    }
461
462
    /**
463
     * To check whether the given character is a HTTP token character
464
     * or not.
465
     *
466
     * @param string $char The character to inspect.
467
     *
468
     * @return boolean True if the given character is a valid HTTP token
469
     *                 character, False otherwise.
470
     */
471 158
    public static function isHttpTokenChar($char)
472
    {
473 158
        return ord($char) < 126 && ord($char) > 31
474 158
            && !self::isHttpSeparator($char);
475
    }
476
477
    /**
478
     * To check whether the given character is a HTTP seperator character.
479
     *
480
     * @param string $char The character to inspect.
481
     *
482
     * @return boolean True if the given character is a valid HTTP seperator
483
     *                 character, False otherwise.
484
     */
485 158
    public static function isHttpSeparator($char)
486
    {
487 158
        return
488 158
            $char == '(' || $char == ')' || $char == '<' || $char == '>' ||
489 158
            $char == '@' || $char == ',' || $char == ';' || $char == ':' ||
490 158
            $char == '\\' || $char == '"' || $char == '/' || $char == '[' ||
491 158
            $char == ']' || $char == '?' || $char == '=' || $char == '{' ||
492 158
            $char == '}' || $char == ' ' || ord($char) == Char::TAB;
493
    }
494
495
    /**
496
     * Read a parameter for a media type/range.
497
     *
498
     * @param string $text        Text to read from.
499
     * @param int    &$textIndex  Pointer in text.
500
     * @param array  &$parameters Array with parameters.
501
     *
502
     * @throws HttpHeaderFailure If found parameter value missing.
503
     * @return void
504
     */
505 131
    public static function readMediaTypeParameter($text, &$textIndex, &$parameters)
506
    {
507 131
        $textStart = $textIndex;
508 131
        if (self::readToken($text, $textIndex)) {
509
            throw new HttpHeaderFailure(
510
                Messages::httpProcessUtilityMediaTypeMissingValue(),
511
                400
512
            );
513
        }
514
515 131
        $parameterName = substr($text, $textStart, $textIndex - $textStart);
516 131
        if ($text[$textIndex] != '=') {
517
            throw new HttpHeaderFailure(
518
                Messages::httpProcessUtilityMediaTypeMissingValue(),
519
                400
520
            );
521
        }
522
523 131
        $textIndex++;
524 131
        $parameterValue
525 131
            = self::readQuotedParameterValue($parameterName, $text, $textIndex);
526 131
        $parameters[] = array($parameterName => $parameterValue);
527
    }
528
529
    /**
530
     * Reads Mime type parameter value for a particular parameter in the
531
     * Content-Type/Accept headers.
532
     *
533
     * @param string $parameterName Name of parameter.
534
     * @param string $text          Header text.
535
     * @param int    &$textIndex    Parsing index in $text.
536
     *
537
     * @return string String representing the value of the $parameterName parameter.
538
     *
539
     * @throws HttpHeaderFailure
540
     */
541 131
    public static function readQuotedParameterValue($parameterName, $text,
542
        &$textIndex
543
    ) {
544 131
        $parameterValue = array();
545 131
        $textLen = strlen($text);
546 131
        $valueIsQuoted = false;
547 131
        if ($textIndex < $textLen) {
548 131
            if ($text[$textIndex] == '"') {
549
                $textIndex++;
550
                $valueIsQuoted = true;
551
            }
552
        }
553
554 131
        while ($textIndex < $textLen) {
555 131
            $currentChar = $text[$textIndex];
556
557 131
            if ($currentChar == '\\' || $currentChar == '"') {
558
                if (!$valueIsQuoted) {
559
                    throw new HttpHeaderFailure(
560
                        Messages::httpProcessUtilityEscapeCharWithoutQuotes(
561
                            $parameterName
562
                        ),
563
                        400
564
                    );
565
                }
566
567
                $textIndex++;
568
569
                // End of quoted parameter value.
570
                if ($currentChar == '"') {
571
                    $valueIsQuoted = false;
572
                    break;
573
                }
574
575
                if ($textIndex >= $textLen) {
576
                    throw new HttpHeaderFailure(
577
                        Messages::httpProcessUtilityEscapeCharAtEnd($parameterName),
578
                        400
579
                    );
580
                }
581
582
                $currentChar = $text[$textIndex];
583 131
            } else if (!self::isHttpTokenChar($currentChar)) {
584
                // If the given character is special, we stop processing.
585 14
                break;
586
            }
587
588 131
            $parameterValue[] = $currentChar;
589 131
            $textIndex++;
590
        }
591
592 131
        if ($valueIsQuoted) {
593
            throw new HttpHeaderFailure(
594
                Messages::httpProcessUtilityClosingQuoteNotFound($parameterName),
595
                400
596
            );
597
        }
598
599 131
        return empty($parameterValue) ? null : implode('', $parameterValue);
600
    }
601
602
    /**
603
     * Reads the numeric part of a quality value substring, normalizing it to 0-1000
604
       rather than the standard 0.000-1.000 ranges.
605
     *
606
     * @param string $text          Text to read qvalue from.
607
     * @param int    &$textIndex    Index into text where the qvalue starts.
608
     * @param int    &$qualityValue After the method executes, the normalized qvalue.
609
     * @param integer $textIndex
610
     *
611
     * @throws HttpHeaderFailure If any error occured while reading and processing
612
     *                           the quality factor.
613
     * @return void
614
     */
615 45
    public static function readQualityValue($text, &$textIndex, &$qualityValue)
616
    {
617 45
        $digit = $text[$textIndex++];
618 45
        if ($digit == '0') {
619 8
            $qualityValue = 0;
620 40
        } else if ($digit == '1') {
621 40
            $qualityValue = 1;
622
        } else {
623
            throw new HttpHeaderFailure(
624
                Messages::httpProcessUtilityMalformedHeaderValue(),
625
                400
626
            );
627
        }
628
629 45
        $textLen = strlen($text);
630 45
        if ($textIndex < $textLen && $text[$textIndex] == '.') {
631 45
            $textIndex++;
632
633 45
            $adjustFactor = 1000;
634 45
            while ($adjustFactor > 1 && $textIndex < $textLen) {
635 45
                $c = $text[$textIndex];
636 45
                $charValue = self::digitToInt32($c);
637 45
                if ($charValue >= 0) {
638 45
                    $textIndex++;
639 45
                    $adjustFactor /= 10;
640 45
                    $qualityValue *= 10;
641 45
                    $qualityValue += $charValue;
642
                } else {
643
                    break;
644
                }
645
            }
646
647 45
            $qualityValue = $qualityValue *= $adjustFactor;
648 45
            if ($qualityValue > 1000) {
649
                // Too high of a value in qvalue.
650 45
                throw new HttpHeaderFailure(
651 45
                    Messages::httpProcessUtilityMalformedHeaderValue(),
652 45
                    400
653 45
                );
654
            }
655
        } else {
656
            $qualityValue *= 1000;
657
        }
658
    }
659
660
    /**
661
     * Converts the specified character from the ASCII range to a digit.
662
     *
663
     * @param string $c Character to convert
664
     *
665
     * @return int The Int32 value for $c, or -1 if it is an element separator.
666
     *
667
     * @throws HttpHeaderFailure If $c is not ASCII value for digit or element
668
     *                           seperator.
669
     */
670 45
    public static function digitToInt32($c)
671
    {
672 45
        if ($c >= '0' && $c <= '9') {
673 45
                return intval($c);
674
        } else {
675
            if (self::isHttpElementSeparator($c)) {
676
                return -1;
677
            } else {
678
                throw new HttpHeaderFailure(
679
                    Messages::httpProcessUtilityMalformedHeaderValue(),
680
                    400
681
                );
682
            }
683
        }
684
    }
685
686
    /**
687
     * Verifies whether the specified character is a valid separator in
688
       an HTTP header list of element.
689
     *
690
     * @param string $c Character to verify
691
     *
692
     * @return boolean true if c is a valid character for separating elements;
693
     *                 false otherwise.
694
     */
695
    public static function isHttpElementSeparator($c)
696
    {
697
        return $c == ',' || $c == ' ' || $c == '\t';
698
    }
699
700
    /**
701
     * Get server key by header
702
     * @param string $headerName Name of header
703
     */
704 84
    public static function headerToServerKey($headerName)
705
    {
706 84
        $name = strtoupper(str_replace('-', '_', $headerName));
707
        switch ($name) {
708 84
            case 'HOST':
709 84
            case 'CONNECTION':
710 84
            case 'CACHE_CONTROL':
711 84
            case 'ORIGIN':
712 84
            case 'USER_AGENT':
713 84
            case 'POSTMAN_TOKEN':
714 84
            case 'ACCEPT':
715 84
            case 'ACCEPT_ENCODING':
716 84
            case 'ACCEPT_LANGUAGE':
717 84
            case 'DATASERVICEVERSION':
718 84
            case 'MAXDATASERVICEVERSION':
719 84
                return 'HTTP_' . $name;
720
        }
721
        return $name;
722
    }
723
}
724