/* Reduced from haproxy-2.7.1: src/tcpcheck.c.  */

/* { dg-additional-options "-Wno-analyzer-too-complex" } */

typedef __SIZE_TYPE__ size_t;
#define NULL ((void *)0)

extern void *calloc(size_t __nmemb, size_t __size)
    __attribute__((__nothrow__, __leaf__)) __attribute__((__malloc__))
    __attribute__((__alloc_size__(1, 2)));
extern char *strdup(const char *__s) __attribute__((__nothrow__, __leaf__))
__attribute__((__malloc__)) __attribute__((__nonnull__(1)));
extern char *strstr(const char *__haystack, const char *__needle)
    __attribute__((__nothrow__, __leaf__)) __attribute__((__pure__))
    __attribute__((__nonnull__(1, 2)));
extern size_t strlen(const char *__s) __attribute__((__nothrow__, __leaf__))
__attribute__((__pure__)) __attribute__((__nonnull__(1)));
struct list {
  struct list *n;
  struct list *p;
};
struct buffer {
  size_t size;
  char *area;
  size_t data;
  size_t head;
};
struct proxy;
struct ist {
  char *ptr;
  size_t len;
};
static inline int isttest(const struct ist ist) { return ist.ptr != NULL; }

enum http_meth_t {
  HTTP_METH_OPTIONS,
  /* [...snip...] */
} __attribute__((packed));

struct http_meth {
  enum http_meth_t meth;
  struct buffer str;
};
enum tcpcheck_send_type {
  /* [...snip...] */
  TCPCHK_SEND_HTTP,
};
enum tcpcheck_rule_type {
  TCPCHK_ACT_SEND = 0,
  /* [...snip...] */
};
struct tcpcheck_http_hdr {
  struct ist name;
  struct list value;
  struct list list;
};
struct tcpcheck_send {
  enum tcpcheck_send_type type;
  union {
    /* [...snip...] */
    struct {
      unsigned int flags;
      struct http_meth meth;
      union {
        struct ist uri;
        /* [...snip...] */
      };
      struct ist vsn;
      struct list hdrs;
      /* [...snip...] */
    } http;
  };
};
struct tcpcheck_rule {
  /* [...snip...] */
  enum tcpcheck_rule_type action;
  /* [...snip...] */
  union {
    /* [...snip...] */
    struct tcpcheck_send send;
    /* [...snip...] */
  };
};
enum http_meth_t find_http_meth(const char *str, const int len);
void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool);
void free_tcpcheck_http_hdr(struct tcpcheck_http_hdr *hdr);

#define ist(str) ({                                                    \
	char *__x = (void *)(str);                                     \
	(struct ist){                                                  \
		.ptr = __x,                                            \
		.len = __builtin_constant_p(str) ?                     \
			((void *)str == (void *)0) ? 0 :               \
			__builtin_strlen(__x) :                        \
			({                                             \
				size_t __l = 0;                        \
				if (__x) for (__l--; __x[++__l]; ) ;   \
				__l;                                   \
			})                                             \
	};                                                             \
})

struct tcpcheck_rule *proxy_parse_httpchk_req(char **args, int cur_arg,
                                              struct proxy *px, char **errmsg) {
  struct tcpcheck_rule *chk = NULL;
  struct tcpcheck_http_hdr *hdr = NULL;
  char *meth = NULL, *uri = NULL, *vsn = NULL;
  char *hdrs, *body;

  hdrs = (*args[cur_arg + 2] ? strstr(args[cur_arg + 2], "\r\n") : NULL);
  body = (*args[cur_arg + 2] ? strstr(args[cur_arg + 2], "\r\n\r\n") : NULL);
  if (hdrs || body) {
    /* [...snip...] */
    goto error;
  }

  chk = calloc(1, sizeof(*chk));
  if (!chk) {
    /* [...snip...] */
    goto error;
  }
  chk->action = TCPCHK_ACT_SEND;
  chk->send.type = TCPCHK_SEND_HTTP;
  chk->send.http.flags |= 0x0004;
  chk->send.http.meth.meth = HTTP_METH_OPTIONS;
  ((&chk->send.http.hdrs)->n = (&chk->send.http.hdrs)->p =
       (&chk->send.http.hdrs));

  if (*args[cur_arg]) {
    if (!*args[cur_arg + 1])
      uri = args[cur_arg];
    else
      meth = args[cur_arg];
  }
  if (*args[cur_arg + 1])
    uri = args[cur_arg + 1];
  if (*args[cur_arg + 2])
    vsn = args[cur_arg + 2];

  if (meth) { /* { dg-bogus "check of 'meth' for NULL after already dereferencing it" } */
    chk->send.http.meth.meth = find_http_meth(meth, strlen(meth));
    chk->send.http.meth.str.area = strdup(meth);
    chk->send.http.meth.str.data = strlen(meth);
    if (!chk->send.http.meth.str.area) {
      /* [...snip...] */
      goto error;
    }
  }
  if (uri) {
    chk->send.http.uri = ist(strdup(uri));
    if (!isttest(chk->send.http.uri)) {
      /* [...snip...] */
      goto error;
    }
  }
  if (vsn) { /* { dg-bogus "check of 'vsn' for NULL after already dereferencing it" } */
    chk->send.http.vsn = ist(strdup(vsn));
    if (!isttest(chk->send.http.vsn)) {
      /* [...snip...] */
      goto error;
    }
  }
  return chk;

error:
  free_tcpcheck_http_hdr(hdr);
  free_tcpcheck(chk, 0);
  return NULL;
}
