| 355 | } |
| 356 | |
| 357 | Result HttpSetCookieView::parse(StringSpan setCookieHeader) |
| 358 | { |
| 359 | *this = {}; |
| 360 | |
| 361 | StringSpan header = HttpHeaderInternal::trimOptionalWhitespace(setCookieHeader); |
| 362 | SC_TRY_MSG(not header.isEmpty(), "Set-Cookie header is empty"); |
| 363 | |
| 364 | const char* data = header.bytesWithoutTerminator(); |
| 365 | const size_t length = header.sizeInBytes(); |
| 366 | size_t firstSemicolon = length; |
| 367 | size_t equals = static_cast<size_t>(-1); |
| 368 | for (size_t idx = 0; idx < length; ++idx) |
| 369 | { |
| 370 | if (data[idx] == ';') |
| 371 | { |
| 372 | firstSemicolon = idx; |
| 373 | break; |
| 374 | } |
| 375 | if (data[idx] == '=' and equals == static_cast<size_t>(-1)) |
| 376 | { |
| 377 | equals = idx; |
| 378 | } |
| 379 | } |
| 380 | SC_TRY_MSG(equals != static_cast<size_t>(-1) and equals < firstSemicolon, "Set-Cookie missing name/value"); |
| 381 | |
| 382 | name = {{data, equals}, false, header.getEncoding()}; |
| 383 | value = {{data + equals + 1, firstSemicolon - equals - 1}, false, header.getEncoding()}; |
| 384 | name = HttpHeaderInternal::trimOptionalWhitespace(name); |
| 385 | value = HttpHeaderInternal::trimOptionalWhitespace(value); |
| 386 | SC_TRY_MSG(not name.isEmpty(), "Set-Cookie cookie name is empty"); |
| 387 | |
| 388 | if (firstSemicolon < length) |
| 389 | { |
| 390 | attributes = {{data + firstSemicolon + 1, length - firstSemicolon - 1}, false, header.getEncoding()}; |
| 391 | } |
| 392 | |
| 393 | HttpSetCookieAttributeIterator it(attributes); |
| 394 | HttpHeaderKeyValue attribute; |
| 395 | while (it.next(attribute)) |
| 396 | { |
| 397 | if (HttpHeaderInternal::equalsIgnoreCase(attribute.name, "Path") and attribute.hasValue) |
| 398 | { |
| 399 | path = attribute.value; |
| 400 | } |
| 401 | else if (HttpHeaderInternal::equalsIgnoreCase(attribute.name, "Domain") and attribute.hasValue) |
| 402 | { |
| 403 | domain = attribute.value; |
| 404 | } |
| 405 | else if (HttpHeaderInternal::equalsIgnoreCase(attribute.name, "Expires") and attribute.hasValue) |
| 406 | { |
| 407 | expires = attribute.value; |
| 408 | } |
| 409 | else if (HttpHeaderInternal::equalsIgnoreCase(attribute.name, "Max-Age") and attribute.hasValue) |
| 410 | { |
| 411 | maxAge = attribute.value; |
| 412 | hasMaxAge = true; |
| 413 | } |
| 414 | else if (HttpHeaderInternal::equalsIgnoreCase(attribute.name, "SameSite") and attribute.hasValue) |
no test coverage detected