Milán Major

netscape-revival

1 branch
Code

sun-java/netscape/net/conn.c

/*
 * @(#)outStr.c	1.2 95/06/14 Warren Harris
 *
 * Copyright (c) 1995 Netscape Communications Corporation. All Rights Reserved.
 *
 */

#include "nsn.h"
#include "prmem.h"
#include "prmon.h"
#include "prlog.h"
#include "prtime.h"

#include "netscape_net_URLConnection.h"
#include "javaString.h"
#include "javaThreads.h"

/******************************************************************************/

PUBLIC void
netscape_net_URLConnection_pCreate(struct Hnetscape_net_URLConnection* this, 
				   struct Hjava_lang_String* urlString,
                                   struct Hjava_lang_String* addressString)
{
    Classnetscape_net_URLConnection* con = unhand(this);
    URL_Struct* url = NULL;
    char* str = NULL;
    char* addr = NULL;
    nsn_JavaStreamData* javaData = NULL;
    MWContext* javaContext;
    LJAppletData* ad;
    NET_ReloadMethod reloadMethod;

    con->pStreamData = 0;
    str = allocCString(urlString);	/* freed by netlib */
    addr = addressString ? allocCString(addressString) : NULL;	/* freed by netlib */
    PR_LOG_BEGIN(NSJAVA, debug,
		 ("URLConnection.pCreate(%s)", str));

    ad = nsn_GetCurrentAppletData();
    reloadMethod = (ad != NULL) ? ad->reloadMethod : NET_NORMAL_RELOAD;
    url = NET_CreateURLStruct(str, reloadMethod);
    if (addr && url) {
      if (NET_SetURLIPAddressString(url, addr)) {
        /* out of memory */
        NET_FreeURLStruct(url);
        url = NULL;
        }
      }
    free(addr);
    if (url == NULL) goto OutOfMemory;
    INCR(urlCount);

    javaData = PR_NEW(nsn_JavaStreamData);
    if (javaData == NULL) goto OutOfMemory;
    INCR(javaDataCount);

    javaData->state = OPENING;
    javaData->refcount = 2; /* Two users, netlib and java */
    javaData->errorStatus = 0;
    javaData->errorMessage = NULL;
    javaData->notifies = 0;
    javaData->netStream = NULL;
    javaData->realContext = nsn_GetCurrentContext();
    javaData->url = url;
    javaData->dataQueue.head = NULL;
    javaData->dataQueue.tail = NULL;

    javaContext = nsn_JavaContext_make(url, javaData);
    if (javaContext == NULL) goto OutOfMemory;

    javaData->javaContext = javaContext;
    url->fe_data = javaData;
    con->pStreamData = (long)javaData;

    PR_LOG_END(NSJAVA, debug,
	       ("URLConnection.pCreate(%s) connected", str));
    
    free(str);
    return;

  OutOfMemory:
    PR_LOG_END(NSJAVA, debug,
	       ("URLConnection.pCreate(%s) raising OutOfMemory", str));
    NSN_FREEIF(javaData);
    DECR(javaDataCount);
    if (url != NULL) {
	NET_FreeURLStruct(url);
	DECR(urlCount);
    }
    SignalError(0, JAVAPKG "OutOfMemoryError", 0);
    free(str);
}

PUBLIC long
netscape_net_URLConnection_getContentLength0(struct Hnetscape_net_URLConnection* this)
{
    nsn_JavaStreamData* javaData = (nsn_JavaStreamData*)unhand(this)->pStreamData;
    URL_Struct* url;
    long result = -1;

    ENTER_METHOD("URLConnection.getContentLength", SILENTLY_FAIL)

    switch (javaData->state) {
      case OPENED:
      case LIBNET_DONE:
	url = javaData->url;
	/* netlib returns 0 for unknown content length, but java wants -1: */
	result = (url->content_length == 0 ? -1 : url->content_length);
	break;
      default:
	break;
    }

    EXIT_METHOD("URLConnection.getContentLength")
    return result;
}

PUBLIC struct Hjava_lang_String*
netscape_net_URLConnection_getContentType0(struct Hnetscape_net_URLConnection* this)
{
    nsn_JavaStreamData* javaData = (nsn_JavaStreamData*)unhand(this)->pStreamData;
    URL_Struct* url;
    struct Hjava_lang_String* result = NULL;

    ENTER_METHOD("URLConnection.getContentType", SILENTLY_FAIL)

    switch (javaData->state) {
      case OPENED:
      case LIBNET_DONE:
	url = javaData->url;
	result = makeJavaString(url->content_type, XP_STRLEN(url->content_type));
	break;
      default:
	break;
    }

    EXIT_METHOD("URLConnection.getContentType")
    return result;
}

static char*
nsn_TimeString(time_t* time)
{
    #define TIME_LENGTH 64
    char* str = malloc(TIME_LENGTH);
    
    uint64	timeInUSec;
    uint64      secToUSec;
    PRTime	expandedTime;

    if (str == NULL) return NULL;
    LL_I2L(timeInUSec, *time);
    LL_I2L(secToUSec, PR_USEC_PER_SEC);
    LL_MUL(timeInUSec, timeInUSec, secToUSec);
#ifndef XP_MAC    
    timeInUSec = PR_ToGMT(timeInUSec);
#endif /* XP_MAC */
    PR_ExplodeTime(&expandedTime, timeInUSec);
    PR_FormatTimeUSEnglish(str, TIME_LENGTH, "%a %b %d %H:%M:%S GMT %Y", &expandedTime);

    return str;
}

PUBLIC struct Hjava_lang_String*
netscape_net_URLConnection_getHeaderField0(struct Hnetscape_net_URLConnection* this,
					   struct Hjava_lang_String* name)
{
    nsn_JavaStreamData* javaData = (nsn_JavaStreamData*)unhand(this)->pStreamData;
    char* str;
    char* resultStr = NULL;
    struct Hjava_lang_String* result = NULL;
    PRBool freeStr = PR_FALSE;
    URL_Struct* url;

    ENTER_METHOD("URLConnection.getHeaderField", SILENTLY_FAIL)

    switch (javaData->state) {
      case OPENED:
      case LIBNET_DONE:
	str = makeCString(name);	/* freed by gc */
	url = javaData->url;

	if (XP_STRCASECMP(str, "Content-type") == 0)
	    resultStr = url->content_type;
	else if (XP_STRCASECMP(str, "Content-encoding") == 0)
	    resultStr = url->content_encoding;
	else if (XP_STRCASECMP(str, "charset") == 0)
	    resultStr = url->charset;
	else if (XP_STRCASECMP(str, "boundary") == 0)
	    resultStr = url->boundary;
	else if (XP_STRCASECMP(str, "Content-name") == 0)
	    resultStr = url->content_name;
	else if (XP_STRCASECMP(str, "Expires") == 0) {
	    resultStr = nsn_TimeString(&url->expires);
	    freeStr = PR_TRUE;
	}
	else if (XP_STRCASECMP(str, "Last-modified") == 0) {
	    resultStr = nsn_TimeString(&url->last_modified);
	    freeStr = PR_TRUE;
	}
	else if (XP_STRCASECMP(str, "Date") == 0) {
	    resultStr = nsn_TimeString(&url->server_date);
	    freeStr = PR_TRUE;
	}
	else if (XP_STRCASECMP(str, "Content-length") == 0) {
	    /* netlib returns 0 for unknown content length, but java wants -1: */
	    resultStr = PR_smprintf("%ld", (url->content_length == 0 ? -1 : url->content_length));
	    freeStr = PR_TRUE;
	}
	else if (XP_STRCASECMP(str, "Server-status") == 0) {
	    resultStr = PR_smprintf("%ld", url->server_status);
	    freeStr = PR_TRUE;
	}
        else {
            uint32 index=0;
            for (; index < url->all_headers.empty_index; index++) {
                if (XP_STRCASECMP(str, url->all_headers.key[index]) == 0) {
                    resultStr = url->all_headers.value[index];
                    break;
                 }
            }
        }

	if (resultStr != NULL)
	    result = makeJavaString(resultStr, XP_STRLEN(resultStr));
	if (freeStr)
	    NSN_FREE(resultStr);
	break;
      default:
	break;
    }

    EXIT_METHOD("URLConnection.getHeaderField")
    return result;
}

PUBLIC struct Hjava_lang_String*
netscape_net_URLConnection_getHeaderFieldKey0(struct Hnetscape_net_URLConnection* this,
					   long index)
{
    nsn_JavaStreamData* javaData = (nsn_JavaStreamData*)unhand(this)->pStreamData;
    char* resultStr = NULL;
    struct Hjava_lang_String* result = NULL;
    URL_Struct* url;

    ENTER_METHOD("URLConnection.getHeaderFieldKey", SILENTLY_FAIL)

    switch (javaData->state) {
      case OPENED:
      case LIBNET_DONE:
	url = javaData->url;

        if (index < url->all_headers.empty_index)
	    resultStr = url->all_headers.key[index];
	if (resultStr != NULL)
	    result = makeJavaString(resultStr, XP_STRLEN(resultStr));
	break;
      default:
	break;
    }

    EXIT_METHOD("URLConnection.getHeaderFieldKey")
    return result;
}

/******************************************************************************/

void
nsn_JavaStream_close(nsn_JavaStreamData* javaData)
{
    PR_LOG_BEGIN(NSJAVA, debug,
		 ("JavaStream.close(%s)", URL_ADDR(javaData)));
    /*
    ** Only when both parties have agreed that they're done can we
    ** destroy the url.
    */
    NET_FreeURLStruct(javaData->url);
    javaData->url = NULL;
    DECR(urlCount);
    
    nsn_DataQueue_clear(&javaData->dataQueue);
    javaData->state = CLOSED;
    
    PR_LOG_END(NSJAVA, debug,
	       ("JavaStream.close(%s)", URL_ADDR(javaData)));
}

void
nsn_JavaStream_javaClose(nsn_JavaStreamData* javaData)
{
    /*
    ** This method is called whenever java initiates the closing of a
    ** connection.
    */

    ENTER_METHOD("JavaStream.javaClose", CANT_HAPPEN)

    /*
    ** Be sure to drop the real context pointer when the connection is
    ** closed. This prevents status messages from being sent to a context
    ** that may already be destroyed.
    */
    javaData->realContext = NULL;

    switch (javaData->state) {
      case OPENED:
      case OPENING:
      case POSTING:
	/*
	** OPENING could happen if we've done the NET_GetURL and then
	** decided to close before netlib could construct the stream.
	*/
	javaData->state = JAVA_DONE;
	PR_LOG(NSJAVA, debug,
	       ("JavaStream.javaClose(%s) java done", URL_ADDR(javaData)));
	break;

      case JAVA_DONE:
      case CLOSED:
	PR_LOG(NSJAVA, debug,
	       ("JavaStream.javaClose(%s): stream already closed!",
		URL_ADDR(javaData)));
	break;

      case LIBNET_DONE:
	/*
	** In this case, libnet has already indicated it's desire to
	** close the stream:
	*/
	PR_LOG(NSJAVA, debug,
	       ("JavaStream.javaClose(%s) java closed",
		URL_ADDR(javaData)));

	nsn_JavaStream_close(javaData);
	break;
      default:
	PR_ASSERT(0);	/* should never get here */
	break;
    }

    /* We can't be needing the input anymore: */
    nsn_DataQueue_clear(&javaData->dataQueue);

    EXIT_METHOD("JavaStream.javaClose")
}

PUBLIC void
netscape_net_URLConnection_close(struct Hnetscape_net_URLConnection* this)
{
    Classnetscape_net_URLConnection* con = unhand(this);
    nsn_JavaStreamData* javaData = (nsn_JavaStreamData*)con->pStreamData;

    ENTER_METHOD("URLConnection.close", IO_EXCEPTION)

    PR_ASSERT(javaData != NULL);		/* javaData was garbage collected */

    nsn_JavaStream_javaClose(javaData);

    con->currentInputStream = 0;
    con->connected = 0;

    EXIT_METHOD("URLConnection.close")
}

PUBLIC void
netscape_net_URLConnection_finalize(struct Hnetscape_net_URLConnection* this)
{
    /* Only called during garbage collection -- consequently no one else
       can be running a method on this connection. Therefore it's ok to finally
       delete the monitor and JavaStreamData object. */
    nsn_JavaStreamData* javaData = (nsn_JavaStreamData*)unhand(this)->pStreamData;

    if (javaData) {
	PR_LOG_BEGIN(NSJAVA, debug,
		     ("URLConnection.pFinalize(%s)", URL_ADDR(javaData)));

	nsn_JavaStream_javaClose(javaData);
	
	/*	If we are done with the data data (no more references),
		dispose of it. */
	
	if (--(javaData->refcount) == 0) {
		if( javaData->url ) {
		    javaData->url->fe_data = NULL;
		}
		if( javaData->javaContext ) {
		    javaData->javaContext->javaContextStreamData = NULL;
		}
		NSN_FREEIF(javaData->errorMessage);
		NSN_FREE(javaData);
		DECR(javaDataCount);
		unhand(this)->pStreamData = 0;
	}

	PR_LOG_END(NSJAVA, debug, ("URLConnection.pFinalize"));
    }
    else {
	PR_LOG(NSJAVA, debug,
	       ("URLConnection.pFinalize: object finalized more than once"));
    }
}

/******************************************************************************/