Use yaz_gettimeofday
[pazpar2-moved-to-github.git] / src / http_command.c
index b191628..b37eca9 100644 (file)
@@ -61,6 +61,7 @@ struct http_session {
 struct http_sessions {
     struct http_session *session_list;
     YAZ_MUTEX mutex;
+    int log_level;
 };
 
 http_sessions_t http_sessions_create(void)
@@ -69,6 +70,7 @@ http_sessions_t http_sessions_create(void)
     hs->session_list = 0;
     hs->mutex = 0;
     pazpar2_mutex_create(&hs->mutex, "http_sessions");
+    hs->log_level = yaz_log_module_level("HTTP");
     return hs;
 }
 
@@ -121,7 +123,7 @@ struct http_session *http_session_create(struct conf_service *service,
 
     r->timeout_iochan = iochan_create(-1, session_timeout, 0, "http_session_timeout");
     iochan_setdata(r->timeout_iochan, r);
-    yaz_log(YLOG_LOG, "%p HTTP session %u created. timeout chan=%p timeout=%d", r, sesid, r->timeout_iochan, service->session_timeout);
+    yaz_log(http_sessions->log_level, "%p Session %u created. timeout chan=%p timeout=%d", r, sesid, r->timeout_iochan, service->session_timeout);
     iochan_settimeout(r->timeout_iochan, service->session_timeout);
 
     iochan_add(service->server->iochan_man, r->timeout_iochan);
@@ -130,22 +132,16 @@ struct http_session *http_session_create(struct conf_service *service,
 
 void http_session_destroy(struct http_session *s)
 {
-    int must_destroy = 1;
+    int must_destroy = 0;
 
     http_sessions_t http_sessions = s->http_sessions;
 
-    yaz_log(YLOG_LOG, "%p HTTP session destroy %u", s, s->session_id);
+    yaz_log(http_sessions->log_level, "%p Session %u destroyed", s, s->session_id);
     yaz_mutex_enter(http_sessions->mutex);
-
-    /* only if http_session destroy was already called, we will allow it
-       to be destroyed */
-    if (s->destroy_counter != s->activity_counter)
-        must_destroy = 0;
-
-    s->destroy_counter = s->activity_counter = 0;
-    if (must_destroy)
-    {
+    /* only if http_session has no active http sessions on it can be destroyed */
+    if (s->destroy_counter == s->activity_counter) {
         struct http_session **p = 0;
+        must_destroy = 1;
         for (p = &http_sessions->session_list; *p; p = &(*p)->next)
             if (*p == s)
             {
@@ -156,12 +152,14 @@ void http_session_destroy(struct http_session *s)
     yaz_mutex_leave(http_sessions->mutex);
     if (must_destroy)
     {   /* destroying for real */
-               yaz_log(YLOG_LOG, "%p HTTP session destroying. session id %u", s, s->session_id);               iochan_destroy(s->timeout_iochan);
+        yaz_log(http_sessions->log_level, "%p Session %u destroyed", s, s->session_id);
+        iochan_destroy(s->timeout_iochan);
         destroy_session(s->psession);
         nmem_destroy(s->nmem);
     }
     else {
-        yaz_log(YLOG_DEBUG, "%p HTTP Session. Active clients on session %u. Waiting for new timeout.", s, s->session_id);
+        yaz_log(http_sessions->log_level, "%p Session %u destroyed delayed. Active clients (%d-%d). Waiting for new timeout.", 
+                s, s->session_id, s->activity_counter, s->destroy_counter);
     }
 
 }
@@ -281,6 +279,15 @@ static struct http_session *locate_session(struct http_channel *c)
     return p;
 }
 
+// Call after use of locate_session, in order to increment the destroy_counter
+static void release_session(struct http_channel *c, struct http_session *session) {
+    http_sessions_t http_sessions = c->http_sessions;
+    yaz_mutex_enter(http_sessions->mutex);
+    if (session)
+        session->destroy_counter++;
+    yaz_mutex_leave(http_sessions->mutex);
+}
+
 // Decode settings parameters and apply to session
 // Syntax: setting[target]=value
 static int process_settings(struct session *se, struct http_request *rq,
@@ -361,11 +368,11 @@ static void cmd_init(struct http_channel *c)
     sesid = make_sessionid();
     s = http_session_create(service, c->http_sessions, sesid);
     
-    yaz_log(YLOG_DEBUG, "HTTP Session init");
+    yaz_log(c->http_sessions->log_level, "%p Session init %u ", s, sesid);
     if (!clear || *clear == '0')
         session_init_databases(s->psession);
     else
-        yaz_log(YLOG_LOG, "No databases preloaded");
+        yaz_log(YLOG_LOG, "HTTP Session %u init: No databases preloaded", sesid);
     
     if (process_settings(s->psession, c->request, c->response) < 0)
         return;
@@ -419,10 +426,13 @@ static void cmd_settings(struct http_channel *c)
 
         xmlFreeDoc(doc);
     }
-    if (process_settings(s->psession, rq, rs) < 0)
+    if (process_settings(s->psession, rq, rs) < 0) {
+        release_session(c,s);
         return;
+    }
     rs->payload = HTTP_COMMAND_RESPONSE_PREFIX "<settings><status>OK</status></settings>";
     http_send_response(c);
+    release_session(c,s);
 }
 
 // Compares two hitsbytarget nodes by hitcount
@@ -545,6 +555,7 @@ static void cmd_termlist(struct http_channel *c)
     wrbuf_puts(c->wrbuf, "</termlist>\n");
     rs->payload = nmem_strdup(rq->channel->nmem, wrbuf_cstr(c->wrbuf));
     http_send_response(c);
+    release_session(c,s);
 }
 
 
@@ -598,6 +609,7 @@ static void cmd_bytarget(struct http_channel *c)
     wrbuf_puts(c->wrbuf, "</bytarget>");
     rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
     http_send_response(c);
+    release_session(c,s);
 }
 
 static void write_metadata(WRBUF w, struct conf_service *service,
@@ -740,6 +752,7 @@ static void cmd_record(struct http_channel *c)
         {
             error(rs, PAZPAR2_RECORD_MISSING, idstr);
         }
+        release_session(c, s);
         return;
     }
     if (offsetstr)
@@ -807,6 +820,7 @@ static void cmd_record(struct http_channel *c)
         http_send_response(c);
     }
     show_single_stop(s->psession, rec);
+    release_session(c, s);
 }
 
 static void cmd_record_ready(void *data)
@@ -848,6 +862,7 @@ static void show_records(struct http_channel *c, int active)
     if (!(sp = reclist_parse_sortparms(c->nmem, sort, s->psession->service)))
     {
         error(rs, PAZPAR2_MALFORMED_PARAMETER_VALUE, "sort");
+        release_session(c, s);
         return;
     }
 
@@ -889,6 +904,7 @@ static void show_records(struct http_channel *c, int active)
     wrbuf_puts(c->wrbuf, "</show>\n");
     rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
     http_send_response(c);
+    release_session(c, s);
 }
 
 static void show_records_ready(void *data)
@@ -918,13 +934,14 @@ static void cmd_show(struct http_channel *c)
             if (session_set_watch(s->psession, SESSION_WATCH_SHOW,
                                   show_records_ready, c, c) != 0)
             {
-                yaz_log(YLOG_DEBUG, "Blocking on cmd_show");
+                yaz_log(c->http_sessions->log_level, "%p Session %u: Blocking on cmd_show", s, s->session_id);
             }
+            release_session(c,s);
             return;
         }
     }
-
     show_records(c, status);
+    release_session(c,s);
 }
 
 static void cmd_ping(struct http_channel *c)
@@ -935,6 +952,7 @@ static void cmd_ping(struct http_channel *c)
         return;
     rs->payload = HTTP_COMMAND_RESPONSE_PREFIX "<ping><status>OK</status></ping>";
     http_send_response(c);
+    release_session(c, s);
 }
 
 static int utf_8_valid(const char *str)
@@ -979,21 +997,25 @@ static void cmd_search(struct http_channel *c)
     if (!query)
     {
         error(rs, PAZPAR2_MISSING_PARAMETER, "query");
+        release_session(c,s);
         return;
     }
     if (!utf_8_valid(query))
     {
         error(rs, PAZPAR2_MALFORMED_PARAMETER_ENCODING, "query");
+        release_session(c,s);
         return;
     }
     code = search(s->psession, query, startrecs, maxrecs, filter, &addinfo);
     if (code)
     {
         error(rs, code, addinfo);
+        release_session(c,s);
         return;
     }
     rs->payload = HTTP_COMMAND_RESPONSE_PREFIX "<search><status>OK</status></search>";
     http_send_response(c);
+    release_session(c,s);
 }
 
 
@@ -1032,6 +1054,7 @@ static void cmd_stat(struct http_channel *c)
     wrbuf_puts(c->wrbuf, "</stat>");
     rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
     http_send_response(c);
+    release_session(c,s);
 }
 
 static void cmd_info(struct http_channel *c)