<commit_before>(in-package #:cl-avm-http-helpers)

(defun parse-etag-condition-header (header)
  "Parse list of ETags for If-Match, If-None-Match headers and return
list of strings or list of single :ANY keyword"
  (when header
    (let ((str (trim header)))
      (if (string= "*" str)
          :ANY
          (let (result
                value)
            (map 'string (named-lambda process-character (c)
                           (cond
                             ;; For simplicity ignore all garbage between quoted values
                             ((and value (char= #\" c))
                              (if result
                                  (push value result)
                                  (setf result (list value)))
                              (setf value nil))
                             ((char= #\" c)
                              (setf value (make-array 10 :fill-pointer 0 :adjustable t :element-type 'character)))
                             (value
                              (vector-push c value)))
                           #\Space)
                 str)
            (nreverse result))))))

(defmacro if-match* ((etag implementation &optional (etag-matched (intern "ETAG-MATCHED" *package*))) &body body)
  (with-gensyms (handler etag-header)
    (once-only ((object-etag etag)
                (impl implementation))
      `(labels ((,handler (,etag-matched)
                  (declare (ignorable ,etag-matched))
                  ,@body))
         (let ((,etag-header (parse-etag-condition-header (http-header :IF-MATCH ,impl))))
           (cond
             ((and ,etag-header ,object-etag)
              ;; Compare and invoke
              ;; FIXME: remove FORMAT here
              ;; FIXME: :ANY must be a value not part of list
              (if (or (eq :ANY ,etag-header) (member (format nil "\"~A\"" ,object-etag)
                                                     ,etag-header
                                                     ;; FIXME: Properly split quotes
                                                     :test #'(lambda (etag item)
                                                               (or (eq :ANY item)
                                                                   (string= etag item)))))
                  (,handler t)
                  (http-status +http-precondition-failed+ ,impl)))
             ((and ,etag-header (not ,object-etag))
              ;; Not found?
              (if (eq :ANY ,etag-header)
                  ;; Requirement from RFC 2616 (12.24)
                  (http-status +http-precondition-failed+ ,impl)
                  (http-status +http-not-found+ ,impl)))<commit_msg>Fix issue with ETag value handling<commit_after>(in-package #:cl-avm-http-helpers)

(defun parse-etag-condition-header (header)
  "Parse list of ETags for If-Match, If-None-Match headers and return
list of strings or list of single :ANY keyword"
  (when header
    (let ((str (trim header)))
      (if (string= "*" str)
          :ANY
          (let (result
                value)
            (map 'string (named-lambda process-character (c)
                           (cond
                             ;; For simplicity ignore all garbage between quoted values
                             ((and value (char= #\" c))
                              (if result
                                  (push value result)
                                  (setf result (list value)))
                              (setf value nil))
                             ((char= #\" c)
                              (setf value (make-array 10 :fill-pointer 0 :adjustable t :element-type 'character)))
                             (value
                              (vector-push c value)))
                           #\Space)
                 str)
            (nreverse result))))))

(defmacro if-match* ((etag implementation &optional (etag-matched (intern "ETAG-MATCHED" *package*))) &body body)
  (with-gensyms (handler etag-header)
    (once-only ((object-etag etag)
                (impl implementation))
      `(labels ((,handler (,etag-matched)
                  (declare (ignorable ,etag-matched))
                  ,@body))
         (let ((,etag-header (parse-etag-condition-header (http-header :IF-MATCH ,impl))))
           (cond
             ((and ,etag-header ,object-etag)
              ;; Compare and invoke
              ;; FIXME: remove FORMAT here
              ;; FIXME: :ANY must be a value not part of list
              (if (or (eq :ANY ,etag-header) (member (format nil "~A" ,object-etag)
                                                     ,etag-header
                                                     ;; FIXME: Properly split quotes
                                                     :test #'(lambda (etag item)
                                                               (or (eq :ANY item)
                                                                   (string= etag item)))))
                  (,handler t)
                  (http-status +http-precondition-failed+ ,impl)))
             ((and ,etag-header (not ,object-etag))
              ;; Not found?
              (if (eq :ANY ,etag-header)
                  ;; Requirement from RFC 2616 (12.24)
                  (http-status +http-precondition-failed+ ,impl)
                  (http-status +http-not-found+ ,impl)))
{'fraction_non_alphanumeric': 0.1075749115950121, 'fraction_numerical': 0.004094546808114647, 'mean_word_length': 1.0975800156128026, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3554898', 'n_tokens_mistral': 1335, 'n_tokens_neox': 1275, 'n_words': 388}