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 }