github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/emswift/emswiftpkg/impl.go (about)

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package emswiftpkg
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"math/rand"
    10  	"net"
    11  	"net/http"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  	"syscall"
    16  	"time"
    17  
    18  	"golang.org/x/sys/unix"
    19  
    20  	"github.com/swiftstack/sortedmap"
    21  
    22  	"github.com/swiftstack/ProxyFS/conf"
    23  	"github.com/swiftstack/ProxyFS/utils"
    24  )
    25  
    26  type swiftAccountStruct struct {
    27  	name               string
    28  	headers            http.Header
    29  	swiftContainerTree sortedmap.LLRBTree // key is swiftContainerStruct.name; value is *swiftContainerStruct
    30  }
    31  
    32  type swiftContainerStruct struct {
    33  	name            string
    34  	swiftAccount    *swiftAccountStruct // back-reference to swiftAccountStruct
    35  	headers         http.Header
    36  	swiftObjectTree sortedmap.LLRBTree //  key is swiftObjectStruct.name; value is *swiftObjectStruct
    37  }
    38  
    39  type swiftObjectStruct struct {
    40  	name           string
    41  	swiftContainer *swiftContainerStruct // back-reference to swiftContainerStruct
    42  	headers        http.Header
    43  	contents       []byte
    44  }
    45  
    46  type configStruct struct {
    47  	AuthIPAddr  string // Only required if Auth Swift Proxy enabled
    48  	AuthTCPPort uint16 // Only required if Auth Swift Proxy enabled
    49  
    50  	JRPCIPAddr  string // Only required if Auth Swift Proxy enabled
    51  	JRPCTCPPort uint16 // Only required if Auth Swift Proxy enabled
    52  
    53  	NoAuthIPAddr  string
    54  	NoAuthTCPPort uint16
    55  
    56  	MaxAccountNameLength   uint64
    57  	MaxContainerNameLength uint64
    58  	MaxObjectNameLength    uint64
    59  	AccountListingLimit    uint64
    60  	ContainerListingLimit  uint64
    61  }
    62  
    63  type authEmulatorStruct struct {
    64  	sync.Mutex
    65  	httpServer          *http.Server
    66  	resolvedJRPCTCPAddr *net.TCPAddr
    67  	wg                  sync.WaitGroup
    68  }
    69  
    70  type noAuthEmulatorStruct struct {
    71  	sync.Mutex
    72  	httpServer *http.Server
    73  	wg         sync.WaitGroup
    74  }
    75  
    76  type globalsStruct struct {
    77  	config          configStruct
    78  	authEmulator    *authEmulatorStruct
    79  	noAuthEmulator  *noAuthEmulatorStruct
    80  	swiftAccountMap map[string]*swiftAccountStruct // key is swiftAccountStruct.name; value is *swiftAccountStruct
    81  }
    82  
    83  var globals globalsStruct
    84  
    85  const (
    86  	startGETInfoMaxRetries = 10
    87  	startGETInfoRetryDelay = 100 * time.Millisecond
    88  )
    89  
    90  const (
    91  	fixedAuthToken           = "AUTH_tk0123456789abcde0123456789abcdef0"
    92  	fixedUserToAccountPrefix = "AUTH_" // Prefixed to User truncated before colon (":") if necessary
    93  )
    94  
    95  type jrpcRequestStruct struct {
    96  	JSONrpc string         `json:"jsonrpc"`
    97  	Method  string         `json:"method"`
    98  	ID      uint64         `json:"id"`
    99  	Params  [1]interface{} `json:"params"`
   100  }
   101  
   102  type jrpcRequestEmptyParamStruct struct{}
   103  
   104  type jrpcResponseIDAndErrorStruct struct {
   105  	ID    uint64 `json:"id"`
   106  	Error string `json:"error"`
   107  }
   108  
   109  type jrpcResponseNoErrorStruct struct {
   110  	ID     uint64      `json:"id"`
   111  	Result interface{} `json:"result"`
   112  }
   113  
   114  type httpRequestHandler struct{}
   115  
   116  type rangeStruct struct {
   117  	startOffset uint64
   118  	stopOffset  uint64
   119  }
   120  
   121  type stringSet map[string]bool
   122  
   123  var headerNameIgnoreSet = stringSet{"Accept": true, "Accept-Encoding": true, "User-Agent": true, "Content-Length": true}
   124  
   125  func start(confMap conf.ConfMap) (err error) {
   126  	err = initializeGlobals(confMap)
   127  	if nil != err {
   128  		return
   129  	}
   130  
   131  	err = startNoAuth()
   132  	if nil != err {
   133  		return
   134  	}
   135  
   136  	err = startAuthIfRequested()
   137  	if nil != err {
   138  		return
   139  	}
   140  
   141  	return
   142  }
   143  
   144  func stop() (err error) {
   145  	err = stopAuthIfRequested()
   146  	if nil != err {
   147  		return
   148  	}
   149  
   150  	err = stopNoAuth()
   151  	if nil != err {
   152  		return
   153  	}
   154  
   155  	uninitializeGlobals()
   156  
   157  	err = nil
   158  	return
   159  }
   160  
   161  func initializeGlobals(confMap conf.ConfMap) (err error) {
   162  	globals.config.AuthIPAddr, err = confMap.FetchOptionValueString("EMSWIFT", "AuthIPAddr")
   163  	if nil == err {
   164  		globals.config.AuthTCPPort, err = confMap.FetchOptionValueUint16("EMSWIFT", "AuthTCPPort")
   165  		if nil != err {
   166  			return
   167  		}
   168  
   169  		globals.config.JRPCIPAddr, err = confMap.FetchOptionValueString("EMSWIFT", "JRPCIPAddr")
   170  		if nil != err {
   171  			return
   172  		}
   173  		globals.config.JRPCTCPPort, err = confMap.FetchOptionValueUint16("EMSWIFT", "JRPCTCPPort")
   174  		if nil != err {
   175  			return
   176  		}
   177  	} else {
   178  		err = nil
   179  		globals.config.AuthIPAddr = ""
   180  		globals.config.AuthTCPPort = 0
   181  	}
   182  
   183  	globals.config.NoAuthIPAddr, err = confMap.FetchOptionValueString("EMSWIFT", "NoAuthIPAddr")
   184  	if nil != err {
   185  		return
   186  	}
   187  	globals.config.NoAuthTCPPort, err = confMap.FetchOptionValueUint16("EMSWIFT", "NoAuthTCPPort")
   188  	if nil != err {
   189  		return
   190  	}
   191  
   192  	globals.config.MaxAccountNameLength, err = confMap.FetchOptionValueUint64("EMSWIFT", "MaxAccountNameLength")
   193  	if nil != err {
   194  		return
   195  	}
   196  	globals.config.MaxContainerNameLength, err = confMap.FetchOptionValueUint64("EMSWIFT", "MaxContainerNameLength")
   197  	if nil != err {
   198  		return
   199  	}
   200  	globals.config.MaxObjectNameLength, err = confMap.FetchOptionValueUint64("EMSWIFT", "MaxObjectNameLength")
   201  	if nil != err {
   202  		return
   203  	}
   204  	globals.config.AccountListingLimit, err = confMap.FetchOptionValueUint64("EMSWIFT", "AccountListingLimit")
   205  	if nil != err {
   206  		return
   207  	}
   208  	globals.config.ContainerListingLimit, err = confMap.FetchOptionValueUint64("EMSWIFT", "ContainerListingLimit")
   209  	if nil != err {
   210  		return
   211  	}
   212  
   213  	globals.authEmulator = nil
   214  	globals.noAuthEmulator = nil
   215  
   216  	globals.swiftAccountMap = make(map[string]*swiftAccountStruct)
   217  
   218  	return
   219  }
   220  
   221  func uninitializeGlobals() {
   222  	globals.config.AuthIPAddr = ""
   223  	globals.config.AuthTCPPort = 0
   224  
   225  	globals.config.NoAuthIPAddr = ""
   226  	globals.config.NoAuthTCPPort = 0
   227  
   228  	globals.config.MaxAccountNameLength = 0
   229  	globals.config.MaxContainerNameLength = 0
   230  	globals.config.MaxObjectNameLength = 0
   231  	globals.config.AccountListingLimit = 0
   232  	globals.config.ContainerListingLimit = 0
   233  
   234  	globals.authEmulator = nil
   235  	globals.noAuthEmulator = nil
   236  
   237  	globals.swiftAccountMap = make(map[string]*swiftAccountStruct)
   238  }
   239  
   240  func startAuthIfRequested() (err error) {
   241  	var (
   242  		authEmulator           *authEmulatorStruct
   243  		startGETInfoNumRetries int
   244  	)
   245  
   246  	if "" == globals.config.AuthIPAddr {
   247  		globals.authEmulator = nil
   248  		err = nil
   249  		return
   250  	}
   251  
   252  	authEmulator = &authEmulatorStruct{
   253  		httpServer: &http.Server{
   254  			Addr: net.JoinHostPort(globals.config.AuthIPAddr, fmt.Sprintf("%d", globals.config.AuthTCPPort)),
   255  		},
   256  	}
   257  	authEmulator.httpServer.Handler = authEmulator
   258  
   259  	authEmulator.resolvedJRPCTCPAddr, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(globals.config.JRPCIPAddr, fmt.Sprintf("%d", globals.config.JRPCTCPPort)))
   260  	if nil != err {
   261  		return
   262  	}
   263  
   264  	authEmulator.wg.Add(1)
   265  
   266  	globals.authEmulator = authEmulator
   267  
   268  	go func() {
   269  		_ = globals.authEmulator.httpServer.ListenAndServe()
   270  		globals.authEmulator.wg.Done()
   271  	}()
   272  
   273  	startGETInfoNumRetries = 0
   274  
   275  	for {
   276  		_, err = http.Get("http://" + globals.authEmulator.httpServer.Addr + "/info")
   277  		if nil == err {
   278  			break
   279  		}
   280  		startGETInfoNumRetries++
   281  		if startGETInfoNumRetries > startGETInfoMaxRetries {
   282  			_ = stopAuthIfRequested()
   283  			err = fmt.Errorf("startAuthIfRequested() failed to establish that authEmulator is up")
   284  			return
   285  		}
   286  		time.Sleep(startGETInfoRetryDelay)
   287  	}
   288  
   289  	err = nil
   290  	return
   291  }
   292  
   293  func stopAuthIfRequested() (err error) {
   294  	if nil == globals.authEmulator {
   295  		err = nil
   296  		return
   297  	}
   298  
   299  	err = globals.authEmulator.httpServer.Close()
   300  	if nil != err {
   301  		return
   302  	}
   303  
   304  	globals.authEmulator.wg.Wait()
   305  
   306  	globals.authEmulator = nil
   307  
   308  	return
   309  }
   310  
   311  func startNoAuth() (err error) {
   312  	var (
   313  		noAuthEmulator         *noAuthEmulatorStruct
   314  		startGETInfoNumRetries int
   315  	)
   316  
   317  	noAuthEmulator = &noAuthEmulatorStruct{
   318  		httpServer: &http.Server{
   319  			Addr: net.JoinHostPort(globals.config.NoAuthIPAddr, fmt.Sprintf("%d", globals.config.NoAuthTCPPort)),
   320  		},
   321  	}
   322  	noAuthEmulator.httpServer.Handler = noAuthEmulator
   323  
   324  	noAuthEmulator.wg.Add(1)
   325  
   326  	globals.noAuthEmulator = noAuthEmulator
   327  
   328  	go func() {
   329  		_ = globals.noAuthEmulator.httpServer.ListenAndServe()
   330  		globals.noAuthEmulator.wg.Done()
   331  	}()
   332  
   333  	startGETInfoNumRetries = 0
   334  
   335  	for {
   336  		_, err = http.Get("http://" + globals.noAuthEmulator.httpServer.Addr + "/info")
   337  		if nil == err {
   338  			break
   339  		}
   340  		startGETInfoNumRetries++
   341  		if startGETInfoNumRetries > startGETInfoMaxRetries {
   342  			_ = stopNoAuth()
   343  			err = fmt.Errorf("startNoAuth() failed to establish that noAuthEmulator is up")
   344  			return
   345  		}
   346  		time.Sleep(startGETInfoRetryDelay)
   347  	}
   348  
   349  	err = nil
   350  	return
   351  }
   352  
   353  func stopNoAuth() (err error) {
   354  	err = globals.noAuthEmulator.httpServer.Close()
   355  	if nil != err {
   356  		return
   357  	}
   358  
   359  	globals.noAuthEmulator.wg.Wait()
   360  
   361  	globals.noAuthEmulator = nil
   362  
   363  	return
   364  }
   365  
   366  func (dummy *authEmulatorStruct) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) {
   367  	var (
   368  		noAuthPath             string
   369  		xAuthKey               string
   370  		xAuthUser              string
   371  		xAuthUserSplit2OnColon []string
   372  		xStorageURL            string
   373  	)
   374  
   375  	// Handle the GET of/on info & AuthURL cases
   376  
   377  	if http.MethodGet == request.Method {
   378  		switch request.URL.Path {
   379  		case "/info":
   380  			_ = request.Body.Close()
   381  			doNoAuthGET(responseWriter, request)
   382  			return
   383  		case "/auth/v1.0":
   384  			_ = request.Body.Close()
   385  			xAuthUser = request.Header.Get("X-Auth-User")
   386  			xAuthKey = request.Header.Get("X-Auth-Key")
   387  			if ("" == xAuthUser) || ("" == xAuthKey) {
   388  				responseWriter.WriteHeader(http.StatusUnauthorized)
   389  				return
   390  			}
   391  			xAuthUserSplit2OnColon = strings.SplitN(xAuthUser, ":", 2)
   392  			xStorageURL = "http://" + globals.authEmulator.httpServer.Addr + "/v1/" + fixedUserToAccountPrefix + xAuthUserSplit2OnColon[0]
   393  			responseWriter.Header().Add("X-Auth-Token", fixedAuthToken)
   394  			responseWriter.Header().Add("X-Storage-Url", xStorageURL)
   395  			return
   396  		default:
   397  			// Fall through to normal processing
   398  		}
   399  	}
   400  
   401  	// Require X-Auth-Token to match fixedAuthToken
   402  
   403  	if fixedAuthToken != request.Header.Get("X-Auth-Token") {
   404  		_ = request.Body.Close()
   405  		responseWriter.WriteHeader(http.StatusUnauthorized)
   406  		return
   407  	}
   408  
   409  	// Require "version" portion of request.URL.Path to be "proxyfs"
   410  
   411  	if !strings.HasPrefix(request.URL.Path, "/proxyfs/") {
   412  		_ = request.Body.Close()
   413  		responseWriter.WriteHeader(http.StatusNotFound)
   414  		return
   415  	}
   416  
   417  	// Branch off to individual request method handlers
   418  
   419  	switch request.Method {
   420  	case http.MethodGet:
   421  		noAuthPath = strings.Replace(request.URL.Path, "proxyfs", "v1", 1)
   422  		request.URL.Path = noAuthPath
   423  		doNoAuthGET(responseWriter, request)
   424  	case http.MethodPut:
   425  		noAuthPath = strings.Replace(request.URL.Path, "proxyfs", "v1", 1)
   426  		request.URL.Path = noAuthPath
   427  		doNoAuthPUT(responseWriter, request)
   428  	case "PROXYFS":
   429  		doAuthPROXYFS(responseWriter, request)
   430  	default:
   431  		responseWriter.WriteHeader(http.StatusMethodNotAllowed)
   432  	}
   433  }
   434  
   435  func doAuthPROXYFS(responseWriter http.ResponseWriter, request *http.Request) {
   436  	var (
   437  		bytesWritten                 int
   438  		bytesWrittenInTotal          int
   439  		err                          error
   440  		jrpcRequest                  []byte
   441  		jrpcResponse                 []byte
   442  		jrpcResponseNestedLeftBraces uint32
   443  		jrpcResponseSingleByte       []byte
   444  		jrpcTCPConn                  *net.TCPConn
   445  	)
   446  
   447  	globals.authEmulator.Lock()
   448  	defer globals.authEmulator.Unlock()
   449  
   450  	jrpcRequest, err = ioutil.ReadAll(request.Body)
   451  	if nil != err {
   452  		panic(err)
   453  	}
   454  	_ = request.Body.Close()
   455  
   456  	jrpcTCPConn, err = net.DialTCP("tcp", nil, globals.authEmulator.resolvedJRPCTCPAddr)
   457  	if nil != err {
   458  		panic(err)
   459  	}
   460  
   461  	bytesWrittenInTotal = 0
   462  
   463  	for bytesWrittenInTotal < len(jrpcRequest) {
   464  		bytesWritten, err = jrpcTCPConn.Write(jrpcRequest[bytesWrittenInTotal:])
   465  		if nil != err {
   466  			panic(err)
   467  		}
   468  		bytesWrittenInTotal += bytesWritten
   469  	}
   470  
   471  	jrpcResponse = make([]byte, 0)
   472  	jrpcResponseSingleByte = make([]byte, 1)
   473  
   474  	_, err = jrpcTCPConn.Read(jrpcResponseSingleByte)
   475  	if nil != err {
   476  		panic(err)
   477  	}
   478  	jrpcResponse = append(jrpcResponse, jrpcResponseSingleByte[0])
   479  
   480  	if '{' != jrpcResponseSingleByte[0] {
   481  		err = fmt.Errorf("Opening character of jrpcResponse must be '{'")
   482  		panic(err)
   483  	}
   484  
   485  	jrpcResponseNestedLeftBraces = 1
   486  
   487  	for 0 < jrpcResponseNestedLeftBraces {
   488  		_, err = jrpcTCPConn.Read(jrpcResponseSingleByte)
   489  		if nil != err {
   490  			panic(err)
   491  		}
   492  		jrpcResponse = append(jrpcResponse, jrpcResponseSingleByte[0])
   493  
   494  		switch jrpcResponseSingleByte[0] {
   495  		case '{':
   496  			jrpcResponseNestedLeftBraces++
   497  		case '}':
   498  			jrpcResponseNestedLeftBraces--
   499  		default:
   500  			// Nothing special to do here
   501  		}
   502  	}
   503  
   504  	err = jrpcTCPConn.Close()
   505  	if nil != err {
   506  		panic(err)
   507  	}
   508  
   509  	responseWriter.Header().Add("Content-Type", "application/json")
   510  	responseWriter.WriteHeader(http.StatusOK)
   511  	_, _ = responseWriter.Write(jrpcResponse)
   512  }
   513  
   514  func (dummy *noAuthEmulatorStruct) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) {
   515  	switch request.Method {
   516  	case http.MethodDelete:
   517  		doNoAuthDELETE(responseWriter, request)
   518  	case http.MethodGet:
   519  		doNoAuthGET(responseWriter, request)
   520  	case http.MethodHead:
   521  		doNoAuthHEAD(responseWriter, request)
   522  	case http.MethodPost:
   523  		doNoAuthPOST(responseWriter, request)
   524  	case http.MethodPut:
   525  		doNoAuthPUT(responseWriter, request)
   526  	default:
   527  		responseWriter.WriteHeader(http.StatusMethodNotAllowed)
   528  	}
   529  }
   530  
   531  func (dummy *globalsStruct) DumpKey(key sortedmap.Key) (keyAsString string, err error) {
   532  	keyAsString = fmt.Sprintf("%v", key)
   533  	err = nil
   534  	return
   535  }
   536  
   537  func (dummy *globalsStruct) DumpValue(value sortedmap.Value) (valueAsString string, err error) {
   538  	valueAsString = fmt.Sprintf("%v", value)
   539  	err = nil
   540  	return
   541  }
   542  
   543  func parsePath(request *http.Request) (infoOnly bool, swiftAccountName string, swiftContainerName string, swiftObjectName string) {
   544  	var (
   545  		pathSplit []string
   546  	)
   547  
   548  	infoOnly = false
   549  	swiftAccountName = ""
   550  	swiftContainerName = ""
   551  	swiftObjectName = ""
   552  
   553  	if "/info" == request.URL.Path {
   554  		infoOnly = true
   555  		return
   556  	}
   557  
   558  	if strings.HasPrefix(request.URL.Path, "/v1/") {
   559  		pathSplit = strings.SplitN(request.URL.Path[4:], "/", 3)
   560  		swiftAccountName = pathSplit[0]
   561  		if 1 == len(pathSplit) {
   562  			swiftContainerName = ""
   563  			swiftObjectName = ""
   564  		} else {
   565  			swiftContainerName = pathSplit[1]
   566  			if 2 == len(pathSplit) {
   567  				swiftObjectName = ""
   568  			} else {
   569  				swiftObjectName = pathSplit[2]
   570  			}
   571  		}
   572  	}
   573  
   574  	return
   575  }
   576  
   577  func parseRangeHeader(request *http.Request, objectLen int) (ranges []rangeStruct, err error) {
   578  	var (
   579  		off                    int
   580  		rangeHeaderValue       string
   581  		rangeHeaderValueSuffix string
   582  		rangeString            string
   583  		rangeStringSlice       []string
   584  		rangesStrings          []string
   585  		rangesStringsIndex     int
   586  		startOffset            int64
   587  		stopOffset             int64
   588  	)
   589  
   590  	rangeHeaderValue = request.Header.Get("Range")
   591  	if "" == rangeHeaderValue {
   592  		ranges = make([]rangeStruct, 0)
   593  		err = nil
   594  		return
   595  	}
   596  
   597  	if !strings.HasPrefix(rangeHeaderValue, "bytes=") {
   598  		err = fmt.Errorf("rangeHeaderValue (%v) does not start with expected \"bytes=\"", rangeHeaderValue)
   599  		return
   600  	}
   601  
   602  	rangeHeaderValueSuffix = rangeHeaderValue[len("bytes="):]
   603  
   604  	rangesStrings = strings.SplitN(rangeHeaderValueSuffix, ",", 2)
   605  
   606  	ranges = make([]rangeStruct, len(rangesStrings))
   607  
   608  	for rangesStringsIndex, rangeString = range rangesStrings {
   609  		rangeStringSlice = strings.SplitN(rangeString, "-", 2)
   610  		if 2 != len(rangeStringSlice) {
   611  			err = fmt.Errorf("rangeHeaderValue (%v) malformed", rangeHeaderValue)
   612  			return
   613  		}
   614  		if "" == rangeStringSlice[0] {
   615  			startOffset = int64(-1)
   616  		} else {
   617  			off, err = strconv.Atoi(rangeStringSlice[0])
   618  			if nil != err {
   619  				err = fmt.Errorf("rangeHeaderValue (%v) malformed (strconv.Atoi() failure: %v)", rangeHeaderValue, err)
   620  				return
   621  			}
   622  			startOffset = int64(off)
   623  		}
   624  
   625  		if "" == rangeStringSlice[1] {
   626  			stopOffset = int64(-1)
   627  		} else {
   628  			off, err = strconv.Atoi(rangeStringSlice[1])
   629  			if nil != err {
   630  				err = fmt.Errorf("rangeHeaderValue (%v) malformed (strconv.Atoi() failure: %v)", rangeHeaderValue, err)
   631  				return
   632  			}
   633  			stopOffset = int64(off)
   634  		}
   635  
   636  		if ((0 > startOffset) && (0 > stopOffset)) || (startOffset > stopOffset) {
   637  			err = fmt.Errorf("rangeHeaderValue (%v) malformed", rangeHeaderValue)
   638  			return
   639  		}
   640  
   641  		if startOffset < 0 {
   642  			startOffset = int64(objectLen) - stopOffset
   643  			if startOffset < 0 {
   644  				err = fmt.Errorf("rangeHeaderValue (%v) malformed...computed startOffset negative", rangeHeaderValue)
   645  				return
   646  			}
   647  			stopOffset = int64(objectLen - 1)
   648  		} else if stopOffset < 0 {
   649  			stopOffset = int64(objectLen - 1)
   650  		} else {
   651  			if stopOffset > int64(objectLen-1) {
   652  				stopOffset = int64(objectLen - 1)
   653  			}
   654  		}
   655  
   656  		ranges[rangesStringsIndex].startOffset = uint64(startOffset)
   657  		ranges[rangesStringsIndex].stopOffset = uint64(stopOffset)
   658  	}
   659  
   660  	err = nil
   661  	return
   662  }
   663  
   664  func locateSwiftAccount(swiftAccountName string) (swiftAccount *swiftAccountStruct, errno syscall.Errno) {
   665  	var (
   666  		ok bool
   667  	)
   668  
   669  	swiftAccount, ok = globals.swiftAccountMap[swiftAccountName]
   670  	if !ok {
   671  		errno = unix.ENOENT
   672  		return
   673  	}
   674  	errno = 0
   675  	return
   676  }
   677  
   678  func createSwiftAccount(swiftAccountName string) (swiftAccount *swiftAccountStruct, errno syscall.Errno) {
   679  	var (
   680  		ok bool
   681  	)
   682  
   683  	_, ok = globals.swiftAccountMap[swiftAccountName]
   684  	if ok {
   685  		errno = unix.EEXIST
   686  		return
   687  	}
   688  	swiftAccount = &swiftAccountStruct{
   689  		name:               swiftAccountName,
   690  		headers:            make(http.Header),
   691  		swiftContainerTree: sortedmap.NewLLRBTree(sortedmap.CompareString, &globals),
   692  	}
   693  	globals.swiftAccountMap[swiftAccountName] = swiftAccount
   694  	errno = 0
   695  	return
   696  }
   697  
   698  func createOrLocateSwiftAccount(swiftAccountName string) (swiftAccount *swiftAccountStruct, wasCreated bool) {
   699  	var (
   700  		ok bool
   701  	)
   702  
   703  	swiftAccount, ok = globals.swiftAccountMap[swiftAccountName]
   704  	if ok {
   705  		wasCreated = false
   706  	} else {
   707  		swiftAccount = &swiftAccountStruct{
   708  			name:               swiftAccountName,
   709  			headers:            make(http.Header),
   710  			swiftContainerTree: sortedmap.NewLLRBTree(sortedmap.CompareString, &globals),
   711  		}
   712  		globals.swiftAccountMap[swiftAccountName] = swiftAccount
   713  		wasCreated = true
   714  	}
   715  	return
   716  }
   717  
   718  func deleteSwiftAccount(swiftAccountName string, force bool) (errno syscall.Errno) {
   719  	var (
   720  		err                             error
   721  		ok                              bool
   722  		swiftAccount                    *swiftAccountStruct
   723  		swiftswiftAccountContainerCount int
   724  	)
   725  
   726  	swiftAccount, ok = globals.swiftAccountMap[swiftAccountName]
   727  	if ok {
   728  		if force {
   729  			// ok if account contains data... we'll forget it
   730  		} else {
   731  			swiftswiftAccountContainerCount, err = swiftAccount.swiftContainerTree.Len()
   732  			if nil != err {
   733  				panic(err)
   734  			}
   735  			if 0 != swiftswiftAccountContainerCount {
   736  				errno = unix.ENOTEMPTY
   737  				return
   738  			}
   739  		}
   740  		delete(globals.swiftAccountMap, swiftAccountName)
   741  	} else {
   742  		errno = unix.ENOENT
   743  		return
   744  	}
   745  	errno = 0
   746  	return
   747  }
   748  
   749  func locateSwiftContainer(swiftAccount *swiftAccountStruct, swiftContainerName string) (swiftContainer *swiftContainerStruct, errno syscall.Errno) {
   750  	var (
   751  		err                   error
   752  		ok                    bool
   753  		swiftContainerAsValue sortedmap.Value
   754  	)
   755  
   756  	swiftContainerAsValue, ok, err = swiftAccount.swiftContainerTree.GetByKey(swiftContainerName)
   757  	if nil != err {
   758  		panic(err)
   759  	}
   760  	if ok {
   761  		swiftContainer = swiftContainerAsValue.(*swiftContainerStruct)
   762  	} else {
   763  		errno = unix.ENOENT
   764  		return
   765  	}
   766  	errno = 0
   767  	return
   768  }
   769  
   770  func createSwiftContainer(swiftAccount *swiftAccountStruct, swiftContainerName string) (swiftContainer *swiftContainerStruct, errno syscall.Errno) {
   771  	var (
   772  		err error
   773  		ok  bool
   774  	)
   775  
   776  	_, ok, err = swiftAccount.swiftContainerTree.GetByKey(swiftContainerName)
   777  	if nil != err {
   778  		panic(err)
   779  	}
   780  	if ok {
   781  		errno = unix.EEXIST
   782  		return
   783  	} else {
   784  		swiftContainer = &swiftContainerStruct{
   785  			name:            swiftContainerName,
   786  			swiftAccount:    swiftAccount,
   787  			headers:         make(http.Header),
   788  			swiftObjectTree: sortedmap.NewLLRBTree(sortedmap.CompareString, &globals),
   789  		}
   790  		_, err = swiftAccount.swiftContainerTree.Put(swiftContainerName, swiftContainer)
   791  		if nil != err {
   792  			panic(err)
   793  		}
   794  	}
   795  	errno = 0
   796  	return
   797  }
   798  
   799  func createOrLocateSwiftContainer(swiftAccount *swiftAccountStruct, swiftContainerName string) (swiftContainer *swiftContainerStruct, wasCreated bool) {
   800  	var (
   801  		err                   error
   802  		ok                    bool
   803  		swiftContainerAsValue sortedmap.Value
   804  	)
   805  
   806  	swiftContainerAsValue, ok, err = swiftAccount.swiftContainerTree.GetByKey(swiftContainerName)
   807  	if nil != err {
   808  		panic(err)
   809  	}
   810  	if ok {
   811  		swiftContainer = swiftContainerAsValue.(*swiftContainerStruct)
   812  		wasCreated = false
   813  	} else {
   814  		swiftContainer = &swiftContainerStruct{
   815  			name:            swiftContainerName,
   816  			swiftAccount:    swiftAccount,
   817  			headers:         make(http.Header),
   818  			swiftObjectTree: sortedmap.NewLLRBTree(sortedmap.CompareString, &globals),
   819  		}
   820  		_, err = swiftAccount.swiftContainerTree.Put(swiftContainerName, swiftContainer)
   821  		if nil != err {
   822  			panic(err)
   823  		}
   824  		wasCreated = true
   825  	}
   826  	return
   827  }
   828  
   829  func deleteSwiftContainer(swiftAccount *swiftAccountStruct, swiftContainerName string) (errno syscall.Errno) {
   830  	var (
   831  		err                       error
   832  		ok                        bool
   833  		swiftContainer            *swiftContainerStruct
   834  		swiftContainerAsValue     sortedmap.Value
   835  		swiftContainerObjectCount int
   836  	)
   837  
   838  	swiftContainerAsValue, ok, err = swiftAccount.swiftContainerTree.GetByKey(swiftContainerName)
   839  	if nil != err {
   840  		panic(err)
   841  	}
   842  	if ok {
   843  		swiftContainer = swiftContainerAsValue.(*swiftContainerStruct)
   844  		swiftContainerObjectCount, err = swiftContainer.swiftObjectTree.Len()
   845  		if nil != err {
   846  			panic(err)
   847  		}
   848  		if 0 != swiftContainerObjectCount {
   849  			errno = unix.ENOTEMPTY
   850  			return
   851  		}
   852  		_, err = swiftAccount.swiftContainerTree.DeleteByKey(swiftContainerName)
   853  		if nil != err {
   854  			panic(err)
   855  		}
   856  	} else {
   857  		errno = unix.ENOENT
   858  		return
   859  	}
   860  	errno = 0
   861  	return
   862  }
   863  
   864  func locateSwiftObject(swiftContainer *swiftContainerStruct, swiftObjectName string) (swiftObject *swiftObjectStruct, errno syscall.Errno) {
   865  	var (
   866  		err                error
   867  		ok                 bool
   868  		swiftObjectAsValue sortedmap.Value
   869  	)
   870  
   871  	swiftObjectAsValue, ok, err = swiftContainer.swiftObjectTree.GetByKey(swiftObjectName)
   872  	if nil != err {
   873  		panic(err)
   874  	}
   875  	if ok {
   876  		swiftObject = swiftObjectAsValue.(*swiftObjectStruct)
   877  	} else {
   878  		errno = unix.ENOENT
   879  		return
   880  	}
   881  	errno = 0
   882  	return
   883  }
   884  
   885  func createSwiftObject(swiftContainer *swiftContainerStruct, swiftObjectName string) (swiftObject *swiftObjectStruct, errno syscall.Errno) {
   886  	var (
   887  		err error
   888  		ok  bool
   889  	)
   890  
   891  	_, ok, err = swiftContainer.swiftObjectTree.GetByKey(swiftObjectName)
   892  	if nil != err {
   893  		panic(err)
   894  	}
   895  	if ok {
   896  		errno = unix.EEXIST
   897  		return
   898  	} else {
   899  		swiftObject = &swiftObjectStruct{name: swiftObjectName, swiftContainer: swiftContainer, contents: []byte{}}
   900  		_, err = swiftContainer.swiftObjectTree.Put(swiftObjectName, swiftObject)
   901  		if nil != err {
   902  			panic(err)
   903  		}
   904  	}
   905  	errno = 0
   906  	return
   907  }
   908  
   909  func createOrLocateSwiftObject(swiftContainer *swiftContainerStruct, swiftObjectName string) (swiftObject *swiftObjectStruct, wasCreated bool) {
   910  	var (
   911  		err                error
   912  		ok                 bool
   913  		swiftObjectAsValue sortedmap.Value
   914  	)
   915  
   916  	swiftObjectAsValue, ok, err = swiftContainer.swiftObjectTree.GetByKey(swiftObjectName)
   917  	if nil != err {
   918  		panic(err)
   919  	}
   920  	if ok {
   921  		swiftObject = swiftObjectAsValue.(*swiftObjectStruct)
   922  		wasCreated = false
   923  	} else {
   924  		swiftObject = &swiftObjectStruct{name: swiftObjectName, swiftContainer: swiftContainer, contents: []byte{}}
   925  		_, err = swiftContainer.swiftObjectTree.Put(swiftObjectName, swiftObject)
   926  		if nil != err {
   927  			panic(err)
   928  		}
   929  		wasCreated = true
   930  	}
   931  	return
   932  }
   933  
   934  func deleteSwiftObject(swiftContainer *swiftContainerStruct, swiftObjectName string) (errno syscall.Errno) {
   935  	var (
   936  		err error
   937  		ok  bool
   938  	)
   939  
   940  	_, ok, err = swiftContainer.swiftObjectTree.GetByKey(swiftObjectName)
   941  	if nil != err {
   942  		panic(err)
   943  	}
   944  	if ok {
   945  		_, err = swiftContainer.swiftObjectTree.DeleteByKey(swiftObjectName)
   946  		if nil != err {
   947  			panic(err)
   948  		}
   949  	} else {
   950  		errno = unix.ENOENT
   951  		return
   952  	}
   953  	errno = 0
   954  	return
   955  }
   956  
   957  func doNoAuthDELETE(responseWriter http.ResponseWriter, request *http.Request) {
   958  	var (
   959  		err                error
   960  		errno              syscall.Errno
   961  		infoOnly           bool
   962  		swiftAccount       *swiftAccountStruct
   963  		swiftAccountName   string
   964  		swiftContainer     *swiftContainerStruct
   965  		swiftContainerName string
   966  		swiftObjectName    string
   967  	)
   968  
   969  	globals.noAuthEmulator.Lock()
   970  	defer globals.noAuthEmulator.Unlock()
   971  
   972  	infoOnly, swiftAccountName, swiftContainerName, swiftObjectName = parsePath(request)
   973  	if infoOnly || ("" == swiftAccountName) {
   974  		responseWriter.WriteHeader(http.StatusForbidden)
   975  	} else {
   976  		if "" == swiftContainerName {
   977  			// DELETE SwiftAccount
   978  			errno = deleteSwiftAccount(swiftAccountName, false)
   979  			switch errno {
   980  			case 0:
   981  				responseWriter.WriteHeader(http.StatusNoContent)
   982  			case unix.ENOENT:
   983  				responseWriter.WriteHeader(http.StatusNotFound)
   984  			case unix.ENOTEMPTY:
   985  				responseWriter.WriteHeader(http.StatusConflict)
   986  			default:
   987  				err = fmt.Errorf("deleteSwiftAccount(\"%v\", false) returned unexpected errno: %v", swiftAccountName, errno)
   988  				panic(err)
   989  			}
   990  		} else {
   991  			// DELETE SwiftContainer or SwiftObject
   992  			swiftAccount, errno = locateSwiftAccount(swiftAccountName)
   993  			switch errno {
   994  			case 0:
   995  				if "" == swiftObjectName {
   996  					// DELETE SwiftContainer
   997  					errno = deleteSwiftContainer(swiftAccount, swiftContainerName)
   998  					switch errno {
   999  					case 0:
  1000  						responseWriter.WriteHeader(http.StatusNoContent)
  1001  					case unix.ENOENT:
  1002  						responseWriter.WriteHeader(http.StatusNotFound)
  1003  					case unix.ENOTEMPTY:
  1004  						responseWriter.WriteHeader(http.StatusConflict)
  1005  					default:
  1006  						err = fmt.Errorf("deleteSwiftContainer(\"%v\") returned unexpected errno: %v", swiftContainerName, errno)
  1007  						panic(err)
  1008  					}
  1009  				} else {
  1010  					// DELETE SwiftObject
  1011  					swiftContainer, errno = locateSwiftContainer(swiftAccount, swiftContainerName)
  1012  					switch errno {
  1013  					case 0:
  1014  						errno = deleteSwiftObject(swiftContainer, swiftObjectName)
  1015  						switch errno {
  1016  						case 0:
  1017  							responseWriter.WriteHeader(http.StatusNoContent)
  1018  						case unix.ENOENT:
  1019  							responseWriter.WriteHeader(http.StatusNotFound)
  1020  						default:
  1021  							err = fmt.Errorf("deleteSwiftObject(\"%v\") returned unexpected errno: %v", swiftObjectName, errno)
  1022  							panic(err)
  1023  						}
  1024  					case unix.ENOENT:
  1025  						responseWriter.WriteHeader(http.StatusNotFound)
  1026  					default:
  1027  						err = fmt.Errorf("locateSwiftContainer(\"%v\") returned unexpected errno: %v", swiftContainerName, errno)
  1028  						panic(err)
  1029  					}
  1030  				}
  1031  			case unix.ENOENT:
  1032  				responseWriter.WriteHeader(http.StatusNotFound)
  1033  			default:
  1034  				err = fmt.Errorf("locateSwiftAccount(\"%v\") returned unexpected errno: %v", swiftAccountName, errno)
  1035  				panic(err)
  1036  			}
  1037  		}
  1038  	}
  1039  }
  1040  
  1041  func doNoAuthGET(responseWriter http.ResponseWriter, request *http.Request) {
  1042  	var (
  1043  		boundaryString          string
  1044  		containerIndex          int
  1045  		containerIndexLimit     int
  1046  		err                     error
  1047  		errno                   syscall.Errno
  1048  		found                   bool
  1049  		headerName              string
  1050  		headerValue             string
  1051  		headerValueSlice        []string
  1052  		infoOnly                bool
  1053  		marker                  string
  1054  		markerSlice             []string
  1055  		objectIndex             int
  1056  		objectIndexLimit        int
  1057  		ok                      bool
  1058  		numContainers           int
  1059  		numObjects              int
  1060  		ranges                  []rangeStruct
  1061  		rS                      rangeStruct
  1062  		swiftAccount            *swiftAccountStruct
  1063  		swiftAccountName        string
  1064  		swiftContainer          *swiftContainerStruct
  1065  		swiftContainerName      string
  1066  		swiftContainerNameAsKey sortedmap.Key
  1067  		swiftObject             *swiftObjectStruct
  1068  		swiftObjectName         string
  1069  		swiftObjectNameAsKey    sortedmap.Key
  1070  	)
  1071  
  1072  	globals.noAuthEmulator.Lock()
  1073  	defer globals.noAuthEmulator.Unlock()
  1074  
  1075  	infoOnly, swiftAccountName, swiftContainerName, swiftObjectName = parsePath(request)
  1076  	if infoOnly {
  1077  		_, _ = responseWriter.Write(utils.StringToByteSlice("{"))
  1078  		_, _ = responseWriter.Write(utils.StringToByteSlice("\"swift\": {"))
  1079  		_, _ = responseWriter.Write(utils.StringToByteSlice("\"max_account_name_length\": " + strconv.Itoa(int(globals.config.MaxAccountNameLength)) + ","))
  1080  		_, _ = responseWriter.Write(utils.StringToByteSlice("\"max_container_name_length\": " + strconv.Itoa(int(globals.config.MaxContainerNameLength)) + ","))
  1081  		_, _ = responseWriter.Write(utils.StringToByteSlice("\"max_object_name_length\": " + strconv.Itoa(int(globals.config.MaxObjectNameLength)) + ","))
  1082  		_, _ = responseWriter.Write(utils.StringToByteSlice("\"account_listing_limit\": " + strconv.Itoa(int(globals.config.AccountListingLimit)) + ","))
  1083  		_, _ = responseWriter.Write(utils.StringToByteSlice("\"container_listing_limit\": " + strconv.Itoa(int(globals.config.ContainerListingLimit))))
  1084  		_, _ = responseWriter.Write(utils.StringToByteSlice("}"))
  1085  		_, _ = responseWriter.Write(utils.StringToByteSlice("}"))
  1086  	} else {
  1087  		if "" == swiftAccountName {
  1088  			responseWriter.WriteHeader(http.StatusForbidden)
  1089  		} else {
  1090  			swiftAccount, errno = locateSwiftAccount(swiftAccountName)
  1091  			switch errno {
  1092  			case 0:
  1093  				if "" == swiftContainerName {
  1094  					// GET SwiftAccount
  1095  					for headerName, headerValueSlice = range swiftAccount.headers {
  1096  						for _, headerValue = range headerValueSlice {
  1097  							responseWriter.Header().Add(headerName, headerValue)
  1098  						}
  1099  					}
  1100  					numContainers, err = swiftAccount.swiftContainerTree.Len()
  1101  					if nil != err {
  1102  						panic(err)
  1103  					}
  1104  					if 0 == numContainers {
  1105  						responseWriter.WriteHeader(http.StatusNoContent)
  1106  					} else {
  1107  						marker = ""
  1108  						markerSlice, ok = request.URL.Query()["marker"]
  1109  						if ok && (0 < len(markerSlice)) {
  1110  							marker = markerSlice[0]
  1111  						}
  1112  						containerIndex, found, err = swiftAccount.swiftContainerTree.BisectRight(marker)
  1113  						if nil != err {
  1114  							panic(err)
  1115  						}
  1116  						if found {
  1117  							containerIndex++
  1118  						}
  1119  						if containerIndex < numContainers {
  1120  							containerIndexLimit = numContainers
  1121  							if (containerIndexLimit - containerIndex) > int(globals.config.AccountListingLimit) {
  1122  								containerIndexLimit = containerIndex + int(globals.config.AccountListingLimit)
  1123  							}
  1124  							for containerIndex < containerIndexLimit {
  1125  								swiftContainerNameAsKey, _, _, err = swiftAccount.swiftContainerTree.GetByIndex(containerIndex)
  1126  								if nil != err {
  1127  									panic(err)
  1128  								}
  1129  								swiftContainerName = swiftContainerNameAsKey.(string)
  1130  								_, _ = responseWriter.Write(utils.StringToByteSlice(swiftContainerName))
  1131  								_, _ = responseWriter.Write([]byte{'\n'})
  1132  								containerIndex++
  1133  							}
  1134  						} else {
  1135  							responseWriter.WriteHeader(http.StatusNoContent)
  1136  						}
  1137  					}
  1138  				} else {
  1139  					// GET SwiftContainer or SwiftObject
  1140  					swiftContainer, errno = locateSwiftContainer(swiftAccount, swiftContainerName)
  1141  					switch errno {
  1142  					case 0:
  1143  						if "" == swiftObjectName {
  1144  							// GET SwiftContainer
  1145  							for headerName, headerValueSlice = range swiftContainer.headers {
  1146  								for _, headerValue = range headerValueSlice {
  1147  									responseWriter.Header().Add(headerName, headerValue)
  1148  								}
  1149  							}
  1150  							numObjects, err = swiftContainer.swiftObjectTree.Len()
  1151  							if nil != err {
  1152  								panic(err)
  1153  							}
  1154  							if 0 == numObjects {
  1155  								responseWriter.WriteHeader(http.StatusNoContent)
  1156  							} else {
  1157  								marker = ""
  1158  								markerSlice, ok = request.URL.Query()["marker"]
  1159  								if ok && (0 < len(markerSlice)) {
  1160  									marker = markerSlice[0]
  1161  								}
  1162  								objectIndex, found, err = swiftContainer.swiftObjectTree.BisectRight(marker)
  1163  								if nil != err {
  1164  									panic(err)
  1165  								}
  1166  								if found {
  1167  									objectIndex++
  1168  								}
  1169  								if objectIndex < numObjects {
  1170  									objectIndexLimit = numObjects
  1171  									if (objectIndexLimit - objectIndex) > int(globals.config.ContainerListingLimit) {
  1172  										objectIndexLimit = objectIndex + int(globals.config.ContainerListingLimit)
  1173  									}
  1174  									for objectIndex < objectIndexLimit {
  1175  										swiftObjectNameAsKey, _, _, err = swiftContainer.swiftObjectTree.GetByIndex(objectIndex)
  1176  										if nil != err {
  1177  											panic(err)
  1178  										}
  1179  										swiftObjectName = swiftObjectNameAsKey.(string)
  1180  										_, _ = responseWriter.Write(utils.StringToByteSlice(swiftObjectName))
  1181  										_, _ = responseWriter.Write([]byte{'\n'})
  1182  										objectIndex++
  1183  									}
  1184  								} else {
  1185  									responseWriter.WriteHeader(http.StatusNoContent)
  1186  								}
  1187  							}
  1188  						} else {
  1189  							// GET SwiftObject
  1190  							swiftObject, errno = locateSwiftObject(swiftContainer, swiftObjectName)
  1191  							switch errno {
  1192  							case 0:
  1193  								for headerName, headerValueSlice = range swiftObject.headers {
  1194  									for _, headerValue = range headerValueSlice {
  1195  										responseWriter.Header().Add(headerName, headerValue)
  1196  									}
  1197  								}
  1198  								ranges, err = parseRangeHeader(request, len(swiftObject.contents))
  1199  								if nil == err {
  1200  									switch len(ranges) {
  1201  									case 0:
  1202  										responseWriter.Header().Add("Content-Type", "application/octet-stream")
  1203  										responseWriter.WriteHeader(http.StatusOK)
  1204  										_, _ = responseWriter.Write(swiftObject.contents)
  1205  									case 1:
  1206  										responseWriter.Header().Add("Content-Type", "application/octet-stream")
  1207  										responseWriter.Header().Add("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ranges[0].startOffset, ranges[0].stopOffset, len(swiftObject.contents)))
  1208  										responseWriter.WriteHeader(http.StatusPartialContent)
  1209  										_, _ = responseWriter.Write(swiftObject.contents[ranges[0].startOffset:(ranges[0].stopOffset + 1)])
  1210  									default:
  1211  										boundaryString = fmt.Sprintf("%016x%016x", rand.Uint64(), rand.Uint64())
  1212  										responseWriter.Header().Add("Content-Type", fmt.Sprintf("multipart/byteranges; boundary=%v", boundaryString))
  1213  										responseWriter.WriteHeader(http.StatusPartialContent)
  1214  										for _, rS = range ranges {
  1215  											_, _ = responseWriter.Write([]byte("--" + boundaryString + "\r\n"))
  1216  											_, _ = responseWriter.Write([]byte("Content-Type: application/octet-stream\r\n"))
  1217  											_, _ = responseWriter.Write([]byte(fmt.Sprintf("Content-Range: bytes %d-%d/%d\r\n", rS.startOffset, rS.stopOffset, len(swiftObject.contents))))
  1218  											_, _ = responseWriter.Write([]byte("\r\n"))
  1219  											_, _ = responseWriter.Write(swiftObject.contents[rS.startOffset:(rS.stopOffset + 1)])
  1220  											_, _ = responseWriter.Write([]byte("\r\n"))
  1221  										}
  1222  										_, _ = responseWriter.Write([]byte("--" + boundaryString + "--"))
  1223  									}
  1224  								} else {
  1225  									responseWriter.WriteHeader(http.StatusBadRequest)
  1226  								}
  1227  							case unix.ENOENT:
  1228  								responseWriter.WriteHeader(http.StatusNotFound)
  1229  							default:
  1230  								err = fmt.Errorf("locateSwiftObject(\"%v\") returned unexpected errno: %v", swiftObjectName, errno)
  1231  								panic(err)
  1232  							}
  1233  						}
  1234  					case unix.ENOENT:
  1235  						responseWriter.WriteHeader(http.StatusNotFound)
  1236  					default:
  1237  						err = fmt.Errorf("locateSwiftContainer(\"%v\") returned unexpected errno: %v", swiftContainerName, errno)
  1238  						panic(err)
  1239  					}
  1240  				}
  1241  			case unix.ENOENT:
  1242  				responseWriter.WriteHeader(http.StatusNotFound)
  1243  			default:
  1244  				err = fmt.Errorf("locateSwiftAccount(\"%v\") returned unexpected errno: %v", swiftAccountName, errno)
  1245  				panic(err)
  1246  			}
  1247  		}
  1248  	}
  1249  }
  1250  
  1251  func doNoAuthHEAD(responseWriter http.ResponseWriter, request *http.Request) {
  1252  	var (
  1253  		err                error
  1254  		errno              syscall.Errno
  1255  		headerName         string
  1256  		headerValue        string
  1257  		headerValueSlice   []string
  1258  		infoOnly           bool
  1259  		swiftAccount       *swiftAccountStruct
  1260  		swiftAccountName   string
  1261  		swiftContainer     *swiftContainerStruct
  1262  		swiftContainerName string
  1263  		swiftObject        *swiftObjectStruct
  1264  		swiftObjectName    string
  1265  	)
  1266  
  1267  	globals.noAuthEmulator.Lock()
  1268  	defer globals.noAuthEmulator.Unlock()
  1269  
  1270  	infoOnly, swiftAccountName, swiftContainerName, swiftObjectName = parsePath(request)
  1271  	if infoOnly || ("" == swiftAccountName) {
  1272  		responseWriter.WriteHeader(http.StatusForbidden)
  1273  	} else {
  1274  		swiftAccount, errno = locateSwiftAccount(swiftAccountName)
  1275  		switch errno {
  1276  		case 0:
  1277  			if "" == swiftContainerName {
  1278  				// HEAD SwiftAccount
  1279  				for headerName, headerValueSlice = range swiftAccount.headers {
  1280  					for _, headerValue = range headerValueSlice {
  1281  						responseWriter.Header().Add(headerName, headerValue)
  1282  					}
  1283  				}
  1284  				responseWriter.WriteHeader(http.StatusNoContent)
  1285  			} else {
  1286  				// HEAD SwiftContainer or SwiftObject
  1287  				swiftContainer, errno = locateSwiftContainer(swiftAccount, swiftContainerName)
  1288  				switch errno {
  1289  				case 0:
  1290  					if "" == swiftObjectName {
  1291  						// HEAD SwiftContainer
  1292  						for headerName, headerValueSlice = range swiftContainer.headers {
  1293  							for _, headerValue = range headerValueSlice {
  1294  								responseWriter.Header().Add(headerName, headerValue)
  1295  							}
  1296  						}
  1297  						responseWriter.WriteHeader(http.StatusNoContent)
  1298  					} else {
  1299  						// HEAD SwiftObject
  1300  						swiftObject, errno = locateSwiftObject(swiftContainer, swiftObjectName)
  1301  						switch errno {
  1302  						case 0:
  1303  							for headerName, headerValueSlice = range swiftObject.headers {
  1304  								for _, headerValue = range headerValueSlice {
  1305  									responseWriter.Header().Add(headerName, headerValue)
  1306  								}
  1307  							}
  1308  							responseWriter.Header().Set("Content-Length", strconv.Itoa(len(swiftObject.contents)))
  1309  							responseWriter.WriteHeader(http.StatusOK)
  1310  						case unix.ENOENT:
  1311  							responseWriter.WriteHeader(http.StatusNotFound)
  1312  						default:
  1313  							err = fmt.Errorf("locateSwiftObject(\"%v\") returned unexpected errno: %v", swiftObjectName, errno)
  1314  							panic(err)
  1315  						}
  1316  					}
  1317  				case unix.ENOENT:
  1318  					responseWriter.WriteHeader(http.StatusNotFound)
  1319  				default:
  1320  					err = fmt.Errorf("locateSwiftContainer(\"%v\") returned unexpected errno: %v", swiftContainerName, errno)
  1321  					panic(err)
  1322  				}
  1323  			}
  1324  		case unix.ENOENT:
  1325  			responseWriter.WriteHeader(http.StatusNotFound)
  1326  		default:
  1327  			err = fmt.Errorf("locateSwiftAccount(\"%v\") returned unexpected errno: %v", swiftAccountName, errno)
  1328  			panic(err)
  1329  		}
  1330  	}
  1331  }
  1332  
  1333  func doNoAuthPOST(responseWriter http.ResponseWriter, request *http.Request) {
  1334  	var (
  1335  		err                 error
  1336  		errno               syscall.Errno
  1337  		headerName          string
  1338  		headerValue         string
  1339  		headerValueSlice    []string
  1340  		headerValueSliceLen int
  1341  		ignoreHeader        bool
  1342  		infoOnly            bool
  1343  		swiftAccount        *swiftAccountStruct
  1344  		swiftAccountName    string
  1345  		swiftContainer      *swiftContainerStruct
  1346  		swiftContainerName  string
  1347  		swiftObject         *swiftObjectStruct
  1348  		swiftObjectName     string
  1349  	)
  1350  
  1351  	globals.noAuthEmulator.Lock()
  1352  	defer globals.noAuthEmulator.Unlock()
  1353  
  1354  	infoOnly, swiftAccountName, swiftContainerName, swiftObjectName = parsePath(request)
  1355  	if infoOnly || ("" == swiftAccountName) {
  1356  		responseWriter.WriteHeader(http.StatusForbidden)
  1357  	} else {
  1358  		swiftAccount, errno = locateSwiftAccount(swiftAccountName)
  1359  		switch errno {
  1360  		case 0:
  1361  			if "" == swiftContainerName {
  1362  				// POST SwiftAccount
  1363  				for headerName, headerValueSlice = range request.Header {
  1364  					_, ignoreHeader = headerNameIgnoreSet[headerName]
  1365  					if !ignoreHeader {
  1366  						headerValueSliceLen = len(headerValueSlice)
  1367  						if 0 < headerValueSliceLen {
  1368  							swiftAccount.headers[headerName] = make([]string, 0, headerValueSliceLen)
  1369  							for _, headerValue = range headerValueSlice {
  1370  								if 0 < len(headerValue) {
  1371  									swiftAccount.headers[headerName] = append(swiftAccount.headers[headerName], headerValue)
  1372  								}
  1373  							}
  1374  							if 0 == len(swiftAccount.headers[headerName]) {
  1375  								delete(swiftAccount.headers, headerName)
  1376  							}
  1377  						}
  1378  					}
  1379  				}
  1380  				responseWriter.WriteHeader(http.StatusNoContent)
  1381  			} else {
  1382  				// POST SwiftContainer or SwiftObject
  1383  				swiftContainer, errno = locateSwiftContainer(swiftAccount, swiftContainerName)
  1384  				switch errno {
  1385  				case 0:
  1386  					if "" == swiftObjectName {
  1387  						// POST SwiftContainer
  1388  						for headerName, headerValueSlice = range request.Header {
  1389  							_, ignoreHeader = headerNameIgnoreSet[headerName]
  1390  							if !ignoreHeader {
  1391  								headerValueSliceLen = len(headerValueSlice)
  1392  								if 0 < headerValueSliceLen {
  1393  									swiftContainer.headers[headerName] = make([]string, 0, headerValueSliceLen)
  1394  									for _, headerValue = range headerValueSlice {
  1395  										if 0 < len(headerValue) {
  1396  											swiftContainer.headers[headerName] = append(swiftContainer.headers[headerName], headerValue)
  1397  										}
  1398  									}
  1399  									if 0 == len(swiftContainer.headers[headerName]) {
  1400  										delete(swiftContainer.headers, headerName)
  1401  									}
  1402  								}
  1403  							}
  1404  						}
  1405  						responseWriter.WriteHeader(http.StatusNoContent)
  1406  					} else {
  1407  						// POST SwiftObject
  1408  						swiftObject, errno = locateSwiftObject(swiftContainer, swiftObjectName)
  1409  						switch errno {
  1410  						case 0:
  1411  							for headerName, headerValueSlice = range request.Header {
  1412  								_, ignoreHeader = headerNameIgnoreSet[headerName]
  1413  								if !ignoreHeader {
  1414  									headerValueSliceLen = len(headerValueSlice)
  1415  									if 0 < headerValueSliceLen {
  1416  										swiftObject.headers[headerName] = make([]string, 0, headerValueSliceLen)
  1417  										for _, headerValue = range headerValueSlice {
  1418  											if 0 < len(headerValue) {
  1419  												swiftObject.headers[headerName] = append(swiftObject.headers[headerName], headerValue)
  1420  											}
  1421  										}
  1422  										if 0 == len(swiftObject.headers[headerName]) {
  1423  											delete(swiftObject.headers, headerName)
  1424  										}
  1425  									}
  1426  								}
  1427  							}
  1428  							responseWriter.WriteHeader(http.StatusNoContent)
  1429  						case unix.ENOENT:
  1430  							responseWriter.WriteHeader(http.StatusNotFound)
  1431  						default:
  1432  							err = fmt.Errorf("locateSwiftObject(\"%v\") returned unexpected errno: %v", swiftObjectName, errno)
  1433  							panic(err)
  1434  						}
  1435  					}
  1436  				case unix.ENOENT:
  1437  					responseWriter.WriteHeader(http.StatusNotFound)
  1438  				default:
  1439  					err = fmt.Errorf("locateSwiftContainer(\"%v\") returned unexpected errno: %v", swiftContainerName, errno)
  1440  					panic(err)
  1441  				}
  1442  			}
  1443  		case unix.ENOENT:
  1444  			responseWriter.WriteHeader(http.StatusNotFound)
  1445  		default:
  1446  			err = fmt.Errorf("locateSwiftAccount(\"%v\") returned unexpected errno: %v", swiftAccountName, errno)
  1447  			panic(err)
  1448  		}
  1449  	}
  1450  }
  1451  
  1452  func doNoAuthPUT(responseWriter http.ResponseWriter, request *http.Request) {
  1453  	var (
  1454  		err                 error
  1455  		errno               syscall.Errno
  1456  		headerName          string
  1457  		headerValue         string
  1458  		headerValueSlice    []string
  1459  		headerValueSliceLen int
  1460  		ignoreHeader        bool
  1461  		infoOnly            bool
  1462  		swiftAccount        *swiftAccountStruct
  1463  		swiftAccountName    string
  1464  		swiftContainer      *swiftContainerStruct
  1465  		swiftContainerName  string
  1466  		swiftObject         *swiftObjectStruct
  1467  		swiftObjectName     string
  1468  		wasCreated          bool
  1469  	)
  1470  
  1471  	globals.noAuthEmulator.Lock()
  1472  	defer globals.noAuthEmulator.Unlock()
  1473  
  1474  	infoOnly, swiftAccountName, swiftContainerName, swiftObjectName = parsePath(request)
  1475  	if infoOnly || ("" == swiftAccountName) {
  1476  		responseWriter.WriteHeader(http.StatusForbidden)
  1477  	} else {
  1478  		if "" == swiftContainerName {
  1479  			// PUT SwiftAccount
  1480  			swiftAccount, wasCreated = createOrLocateSwiftAccount(swiftAccountName)
  1481  			if wasCreated {
  1482  				swiftAccount.headers = make(http.Header)
  1483  			}
  1484  			for headerName, headerValueSlice = range request.Header {
  1485  				_, ignoreHeader = headerNameIgnoreSet[headerName]
  1486  				if !ignoreHeader {
  1487  					headerValueSliceLen = len(headerValueSlice)
  1488  					if 0 < headerValueSliceLen {
  1489  						swiftAccount.headers[headerName] = make([]string, 0, headerValueSliceLen)
  1490  						for _, headerValue = range headerValueSlice {
  1491  							if 0 < len(headerValue) {
  1492  								swiftAccount.headers[headerName] = append(swiftAccount.headers[headerName], headerValue)
  1493  							}
  1494  						}
  1495  						if 0 == len(swiftAccount.headers[headerName]) {
  1496  							delete(swiftAccount.headers, headerName)
  1497  						}
  1498  					}
  1499  				}
  1500  			}
  1501  			if wasCreated {
  1502  				responseWriter.WriteHeader(http.StatusCreated)
  1503  			} else {
  1504  				responseWriter.WriteHeader(http.StatusAccepted)
  1505  			}
  1506  		} else {
  1507  			// PUT SwiftContainer or SwiftObject
  1508  			swiftAccount, errno = locateSwiftAccount(swiftAccountName)
  1509  			switch errno {
  1510  			case 0:
  1511  				if "" == swiftObjectName {
  1512  					// PUT SwiftContainer
  1513  					swiftContainer, wasCreated = createOrLocateSwiftContainer(swiftAccount, swiftContainerName)
  1514  					if wasCreated {
  1515  						swiftContainer.headers = make(http.Header)
  1516  					}
  1517  					for headerName, headerValueSlice = range request.Header {
  1518  						_, ignoreHeader = headerNameIgnoreSet[headerName]
  1519  						if !ignoreHeader {
  1520  							headerValueSliceLen = len(headerValueSlice)
  1521  							if 0 < headerValueSliceLen {
  1522  								swiftContainer.headers[headerName] = make([]string, 0, headerValueSliceLen)
  1523  								for _, headerValue = range headerValueSlice {
  1524  									if 0 < len(headerValue) {
  1525  										swiftContainer.headers[headerName] = append(swiftContainer.headers[headerName], headerValue)
  1526  									}
  1527  								}
  1528  								if 0 == len(swiftContainer.headers[headerName]) {
  1529  									delete(swiftContainer.headers, headerName)
  1530  								}
  1531  							}
  1532  						}
  1533  					}
  1534  					if wasCreated {
  1535  						responseWriter.WriteHeader(http.StatusCreated)
  1536  					} else {
  1537  						responseWriter.WriteHeader(http.StatusAccepted)
  1538  					}
  1539  				} else {
  1540  					// PUT SwiftObject
  1541  					swiftContainer, errno = locateSwiftContainer(swiftAccount, swiftContainerName)
  1542  					switch errno {
  1543  					case 0:
  1544  						swiftObject, wasCreated = createOrLocateSwiftObject(swiftContainer, swiftObjectName)
  1545  						if wasCreated {
  1546  							swiftObject.headers = make(http.Header)
  1547  						}
  1548  						for headerName, headerValueSlice = range request.Header {
  1549  							_, ignoreHeader = headerNameIgnoreSet[headerName]
  1550  							if !ignoreHeader {
  1551  								headerValueSliceLen = len(headerValueSlice)
  1552  								if 0 < headerValueSliceLen {
  1553  									swiftObject.headers[headerName] = make([]string, 0, headerValueSliceLen)
  1554  									for _, headerValue = range headerValueSlice {
  1555  										if 0 < len(headerValue) {
  1556  											swiftObject.headers[headerName] = append(swiftObject.headers[headerName], headerValue)
  1557  										}
  1558  									}
  1559  									if 0 == len(swiftObject.headers[headerName]) {
  1560  										delete(swiftObject.headers, headerName)
  1561  									}
  1562  								}
  1563  							}
  1564  						}
  1565  						swiftObject.contents, _ = ioutil.ReadAll(request.Body)
  1566  						if wasCreated {
  1567  							responseWriter.WriteHeader(http.StatusCreated)
  1568  						} else {
  1569  							responseWriter.WriteHeader(http.StatusCreated)
  1570  						}
  1571  					case unix.ENOENT:
  1572  						responseWriter.WriteHeader(http.StatusForbidden)
  1573  					default:
  1574  						err = fmt.Errorf("locateSwiftContainer(\"%v\") returned unexpected errno: %v", swiftContainerName, errno)
  1575  						panic(err)
  1576  					}
  1577  				}
  1578  			case unix.ENOENT:
  1579  				responseWriter.WriteHeader(http.StatusForbidden)
  1580  			default:
  1581  				err = fmt.Errorf("locateSwiftAccount(\"%v\") returned unexpected errno: %v", swiftAccountName, errno)
  1582  				panic(err)
  1583  			}
  1584  		}
  1585  	}
  1586  }