//------------------------------------------------------------------------- // Desc: URL parsing. // Tabs: 3 // // Copyright (c) 1998-2000,2002-2003,2005-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public // License as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, contact Novell, Inc. // // To contact Novell about this file by physical or electronic mail, // you may find current contact information at www.novell.com // // $Id: furl.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ //------------------------------------------------------------------------- #include "flaimsys.h" #define FLAIM_PROTOCOL_NAME "x-flaim" #define FLAIM_PROTOCOL_NAME_LEN 7 #define TCP_SUB_PROTOCOL_NAME ":tcp://" #define TCP_SUB_PROTOCOL_NAME_LEN 7 #define STREAM_SUB_PROTOCOL_NAME ":stream://" #define STREAM_SUB_PROTOCOL_NAME_LEN 10 #define NO_SUB_PROTOCOL_NAME "://" #define NO_SUB_PROTOCOL_NAME_LEN 3 #define FLAIM_DEFAULT_PORT 1677 /**************************************************************************** Public: FUrl constructor, destructor ****************************************************************************/ FUrl::FUrl() { m_iPort = -1; m_iSubProtocol = NO_SUB_PROTOCOL; m_bRelative = FALSE; m_pucAlloc = NULL; m_pszHostName = NULL; m_pszFileName = NULL; m_uiAddrType = FLM_CS_NO_ADDR; m_pszIPName = NULL; m_ui32IPAddr = 0; f_memset( m_pszAddr, 0, FLM_CS_MAX_ADDR_LEN); } FUrl::~FUrl() { Reset(); } /**************************************************************************** Public: FUrl::Reset Desc: Reset members of the URL - freeing memory, etc. ****************************************************************************/ void FUrl::Reset() { m_iPort = -1; m_iSubProtocol = NO_SUB_PROTOCOL; m_bRelative = FALSE; f_free( &m_pucAlloc); m_pszHostName = NULL; m_pszFileName = NULL; m_bLocal = FALSE; f_free( (void **)&m_pszIPName); m_ui32IPAddr = 0; m_uiAddrType = FLM_CS_NO_ADDR; f_memset( m_pszAddr, 0, FLM_CS_MAX_ADDR_LEN); } /**************************************************************************** Public: FUrl::SetUrl Desc: Parse the string passed in and setup the members of the URL. ****************************************************************************/ RCODE FUrl::SetUrl( const char * pszUrlStr) { RCODE rc = FERR_OK; FLMUINT uiAllocLen; char * pucTmp; const char * pucCurrent; const char * pszFileName = NULL; const char * pszHostName = NULL; FLMINT iHostNameLen = 0; FLMINT iPort = -1; FLMINT iSubProtocol = NO_SUB_PROTOCOL; FLMBOOL bRelative = FALSE; /* Clear out the current URL. */ Reset(); /* See if the string begins with our protocol name. If not, assume that it is a file name. */ if ((f_strncmp( pszUrlStr, FLAIM_PROTOCOL_NAME, FLAIM_PROTOCOL_NAME_LEN) != 0) || ((f_strncmp( pszUrlStr + FLAIM_PROTOCOL_NAME_LEN, TCP_SUB_PROTOCOL_NAME, TCP_SUB_PROTOCOL_NAME_LEN) != 0) && (f_strncmp( pszUrlStr + FLAIM_PROTOCOL_NAME_LEN, STREAM_SUB_PROTOCOL_NAME, STREAM_SUB_PROTOCOL_NAME_LEN) != 0) && (f_strncmp( pszUrlStr + FLAIM_PROTOCOL_NAME_LEN, NO_SUB_PROTOCOL_NAME, NO_SUB_PROTOCOL_NAME_LEN) != 0))) { bRelative = FALSE; pszFileName = pszUrlStr; m_bLocal = TRUE; } else { pucCurrent = pszUrlStr + FLAIM_PROTOCOL_NAME_LEN; if( f_strncmp( pucCurrent, TCP_SUB_PROTOCOL_NAME, TCP_SUB_PROTOCOL_NAME_LEN) == 0) { iSubProtocol = TCP_SUB_PROTOCOL; pucCurrent += TCP_SUB_PROTOCOL_NAME_LEN; } else if( f_strncmp( pucCurrent, STREAM_SUB_PROTOCOL_NAME, STREAM_SUB_PROTOCOL_NAME_LEN) == 0) { iSubProtocol = STREAM_SUB_PROTOCOL; pucCurrent += STREAM_SUB_PROTOCOL_NAME_LEN; m_uiAddrType = FLM_CS_STREAM_ADDR; } else { iSubProtocol = NO_SUB_PROTOCOL; pucCurrent += NO_SUB_PROTOCOL_NAME_LEN; } /* If the next character is NOT a slash, we have a host name (or stream name) and optionally a port number */ if( *pucCurrent != '/') { FLMINT iAddrPos; FLMINT iAddrSlot; FLMUINT uiTmpVal; const char * pucNamePos; iPort = FLAIM_DEFAULT_PORT; pszHostName = pucCurrent; while( (*pucCurrent) && (*pucCurrent != '/') && (*pucCurrent != ':')) { iHostNameLen++; pucCurrent++; } /* It is invalid to have an empty host name */ if( !iHostNameLen) { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } /* If this is a URL that does not include a file path, we are done */ if( !(*pucCurrent)) { goto Done; } /* See if we got a colon. If so, extract the port number. */ if( *pucCurrent == ':') { iPort = 0; /* Increment past colon. */ pucCurrent++; /* Make sure we have at least one digit. */ if( (*pucCurrent < '0') || (*pucCurrent > '9')) { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } /* Go until string termination or another backslash. */ while( (*pucCurrent) && (*pucCurrent != '/')) { if ((*pucCurrent < '0') || (*pucCurrent > '9')) { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } iPort *= 10; iPort += (FLMINT)(*pucCurrent - '0'); pucCurrent++; } } if( iSubProtocol != STREAM_SUB_PROTOCOL) { m_uiAddrType = FLM_CS_IP_ADDR; } /* See if the host name is an IP address. If it is an address, extract it. */ /* Dotted IP Address. The format of an IP address is 000.000.000.000 where each dot-separated value can vary in length from 1 to 3 characters. */ iAddrSlot = 0; uiTmpVal = 0; pucNamePos = pszHostName; for( iAddrPos = 0; iAddrPos < iHostNameLen; iAddrPos++) { switch( *pucNamePos) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { uiTmpVal *= 10; uiTmpVal += (FLMUINT)(*pucNamePos - '0'); break; } case '.': { if( iAddrSlot >= 4) { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } ((FLMBYTE *)(&m_ui32IPAddr))[ iAddrSlot++] = (FLMBYTE)uiTmpVal; uiTmpVal = 0; break; } default: { // The buffer does not contain an address. Cause the // loop to terminate. iAddrPos = iHostNameLen; iAddrSlot = 3; continue; } } pucNamePos++; } if( iAddrSlot != 3) { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } /* By now we better be on another slash */ if( *pucCurrent != '/') { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } } /* Increment past slash. */ pucCurrent++; /* See if there are any keywords. */ if( f_strnicmp( pucCurrent, "RELATIVE.", 9) == 0) { pucCurrent += 9; /* Better have specified a host name - RELATIVE is only valid when talking to a server. */ if (!iHostNameLen) { rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; } /* Treat the rest of the string after the "RELATIVE." as a relative file name. */ bRelative = TRUE; pszFileName = pucCurrent; } else if( f_strnicmp( pucCurrent, "ABSOLUTE.", 9) == 0) { pucCurrent += 9; /* Treat the rest of the string after the "ABSOLUTE." as an absolute file name. */ bRelative = FALSE; pszFileName = pucCurrent; } else { /* No keywords, so default case is to treat the rest of the string as a relative file name. */ bRelative = TRUE; pszFileName = pucCurrent; } } /* Make one allocation for everything that is to be copied. */ Done: uiAllocLen = 0; if( pszFileName) { uiAllocLen += (FLMUINT)(f_strlen( pszFileName) + 1); } if (iHostNameLen) { uiAllocLen += (FLMUINT)(iHostNameLen + 1); } if (RC_BAD( rc = f_alloc( uiAllocLen, &m_pucAlloc))) { goto Exit; } m_iSubProtocol = iSubProtocol; m_bRelative = bRelative; pucTmp = m_pucAlloc; m_iPort = iPort; if (iHostNameLen) { f_memcpy( pucTmp, pszHostName, iHostNameLen); pucTmp[ iHostNameLen] = 0; m_pszHostName = pucTmp; pucTmp += (iHostNameLen + 1); if( iHostNameLen + 1 <= FLM_CS_MAX_ADDR_LEN) { f_strcpy( m_pszAddr, m_pszHostName); } else { rc = RC_SET( FERR_MEM); goto Exit; } } if( pszFileName) { f_strcpy( pucTmp, pszFileName); m_pszFileName = pucTmp; } else { m_pszFileName = NULL; } Exit: return( rc); }